Wrap the wide-char enumerating functions instead of the ASCII
[dsound-openal.git] / primary.c
blob440c14f9152fb8f51b64cb28153f0c04796e4741
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(This->ref == 1)
492 This->flags = 0;
494 return ret;
497 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
499 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
500 LONG ret;
502 ret = InterlockedDecrement(&This->ref);
504 return ret;
507 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
509 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
511 TRACE("(%p)->(%p)\n", iface, caps);
513 if(!caps || caps->dwSize < sizeof(*caps))
515 WARN("Invalid DSBCAPS (%p, %u)\n", caps, caps ? caps->dwSize : 0);
516 return DSERR_INVALIDPARAM;
519 EnterCriticalSection(&This->crst);
520 caps->dwFlags = This->flags;
521 caps->dwBufferBytes = This->buf_size;
522 caps->dwUnlockTransferRate = 0;
523 caps->dwPlayCpuOverhead = 0;
524 LeaveCriticalSection(&This->crst);
526 return DS_OK;
529 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
531 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
532 HRESULT hr = DSERR_PRIOLEVELNEEDED;
534 EnterCriticalSection(&This->crst);
535 if(This->write_emu)
536 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
537 LeaveCriticalSection(&This->crst);
539 return hr;
542 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
544 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
545 HRESULT hr = S_OK;
546 UINT size;
548 if(!wfx && !written)
550 WARN("Cannot report format or format size\n");
551 return DSERR_INVALIDPARAM;
554 EnterCriticalSection(&This->crst);
555 size = sizeof(This->format.Format) + This->format.Format.cbSize;
556 if(written)
557 *written = size;
558 if(wfx)
560 if(allocated < size)
561 hr = DSERR_INVALIDPARAM;
562 else
563 memcpy(wfx, &This->format.Format, size);
565 LeaveCriticalSection(&This->crst);
567 return hr;
570 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
572 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
573 HRESULT hr = S_OK;
575 TRACE("(%p)->(%p)\n", iface, volume);
577 if(!volume)
578 return DSERR_INVALIDPARAM;
580 EnterCriticalSection(&This->crst);
581 if(!(This->flags & DSBCAPS_CTRLVOLUME))
582 hr = DSERR_CONTROLUNAVAIL;
583 else
585 ALfloat gain;
586 LONG vol;
588 setALContext(This->ctx);
589 alGetListenerf(AL_GAIN, &gain);
590 getALError();
591 popALContext();
593 vol = gain_to_mB(gain);
594 vol = max(vol, DSBVOLUME_MIN);
595 *volume = min(vol, DSBVOLUME_MAX);
597 LeaveCriticalSection(&This->crst);
599 return hr;
602 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
604 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
605 HRESULT hr = S_OK;
607 WARN("(%p)->(%p): semi-stub\n", iface, pan);
609 if(!pan)
610 return DSERR_INVALIDPARAM;
612 EnterCriticalSection(&This->crst);
613 if(This->write_emu)
614 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
615 else if(!(This->flags & DSBCAPS_CTRLPAN))
616 hr = DSERR_CONTROLUNAVAIL;
617 else
618 *pan = 0;
619 LeaveCriticalSection(&This->crst);
621 return hr;
624 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
626 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
627 HRESULT hr = S_OK;
629 WARN("(%p)->(%p): semi-stub\n", iface, freq);
631 if(!freq)
632 return DSERR_INVALIDPARAM;
634 EnterCriticalSection(&This->crst);
635 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
636 hr = DSERR_CONTROLUNAVAIL;
637 else
638 *freq = This->format.Format.nSamplesPerSec;
639 LeaveCriticalSection(&This->crst);
641 return hr;
644 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
646 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
648 TRACE("(%p)->(%p)\n", iface, status);
650 if(!status)
651 return DSERR_INVALIDPARAM;
653 EnterCriticalSection(&This->crst);
655 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
656 if((This->flags&DSBCAPS_LOCDEFER))
657 *status |= DSBSTATUS_LOCHARDWARE;
659 if(This->stopped)
661 DWORD i, state;
662 HRESULT hr;
664 for(i = 0;i < This->nbuffers;++i)
666 hr = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &state);
667 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
668 break;
670 if(i == This->nbuffers)
672 /* Primary stopped and no buffers playing.. */
673 *status = 0;
677 LeaveCriticalSection(&This->crst);
679 return S_OK;
682 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
684 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
685 HRESULT hr = S_OK;
687 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
689 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
691 WARN("Bad DSBDESC for primary buffer\n");
692 return DSERR_INVALIDPARAM;
694 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
695 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
696 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
698 WARN("Bad dwFlags %08x\n", desc->dwFlags);
699 return DSERR_INVALIDPARAM;
702 EnterCriticalSection(&This->crst);
703 /* Should be 0 if not initialized */
704 if(This->flags)
706 hr = DSERR_ALREADYINITIALIZED;
707 goto out;
710 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
712 DSBUFFERDESC emudesc;
713 DS8Buffer *emu;
715 if(This->write_emu)
717 ERR("There shouldn't be a write_emu!\n");
718 IDirectSoundBuffer8_Release(This->write_emu);
719 This->write_emu = NULL;
722 memset(&emudesc, 0, sizeof(emudesc));
723 emudesc.dwSize = sizeof(emudesc);
724 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
725 /* Dont play last incomplete sample */
726 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
727 emudesc.lpwfxFormat = &This->format.Format;
729 hr = DS8Buffer_Create(&emu, This, NULL);
730 if(SUCCEEDED(hr))
732 This->write_emu = &emu->IDirectSoundBuffer8_iface;
733 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
734 if(FAILED(hr))
736 IDirectSoundBuffer8_Release(This->write_emu);
737 This->write_emu = NULL;
742 if(SUCCEEDED(hr))
743 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
744 out:
745 LeaveCriticalSection(&This->crst);
746 return hr;
749 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
751 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
752 HRESULT hr = DSERR_PRIOLEVELNEEDED;
754 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
756 EnterCriticalSection(&This->crst);
757 if(This->write_emu)
758 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
759 LeaveCriticalSection(&This->crst);
761 return hr;
764 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
766 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
767 HRESULT hr;
769 TRACE("(%p)->(%u, %u, %u)\n", iface, res1, res2, flags);
771 if(!(flags & DSBPLAY_LOOPING))
773 WARN("Flags (%08x) not set to DSBPLAY_LOOPING\n", flags);
774 return DSERR_INVALIDPARAM;
777 EnterCriticalSection(&This->crst);
778 hr = S_OK;
779 if(This->write_emu)
780 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
781 if(SUCCEEDED(hr))
782 This->stopped = FALSE;
783 LeaveCriticalSection(&This->crst);
785 return hr;
788 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
790 WARN("(%p)->(%u)\n", iface, pos);
791 return DSERR_INVALIDCALL;
794 /* Just assume the format is crap, and clean up the damage */
795 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
797 if(from->wFormatTag == WAVE_FORMAT_PCM)
799 wfx->cbSize = 0;
800 if(from->wBitsPerSample == 8 ||
801 from->wBitsPerSample == 16 ||
802 from->wBitsPerSample == 24 ||
803 from->wBitsPerSample == 32)
804 wfx->wBitsPerSample = from->wBitsPerSample;
806 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
808 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
809 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
810 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
812 /* Fail silently.. */
813 if(from->cbSize < size)
814 return;
815 if(!fromx->Samples.wValidBitsPerSample &&
816 !fromx->Format.wBitsPerSample)
817 return;
819 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
820 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
822 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
823 return;
826 wfe->Format.wBitsPerSample = from->wBitsPerSample;
827 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
828 if(!wfe->Samples.wValidBitsPerSample)
829 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
830 wfe->Format.cbSize = size;
831 wfe->dwChannelMask = fromx->dwChannelMask;
832 wfe->SubFormat = fromx->SubFormat;
834 else
836 ERR("Unhandled format tag %04x\n", from->wFormatTag);
837 return;
840 if(from->nChannels)
841 wfx->nChannels = from->nChannels;
842 wfx->wFormatTag = from->wFormatTag;
843 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
844 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
845 wfx->nSamplesPerSec = from->nSamplesPerSec;
846 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
847 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
850 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
852 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
853 HRESULT hr = S_OK;
854 ALCint freq;
856 TRACE("(%p)->(%p)\n", iface, wfx);
858 if(!wfx)
860 WARN("Missing format\n");
861 return DSERR_INVALIDPARAM;
864 EnterCriticalSection(&This->crst);
866 if(This->parent->prio_level < DSSCL_PRIORITY)
868 hr = DSERR_PRIOLEVELNEEDED;
869 goto out;
872 TRACE("Requested primary format:\n"
873 " FormatTag = %04x\n"
874 " Channels = %u\n"
875 " SamplesPerSec = %u\n"
876 " AvgBytesPerSec = %u\n"
877 " BlockAlign = %u\n"
878 " BitsPerSample = %u\n",
879 wfx->wFormatTag, wfx->nChannels,
880 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
881 wfx->nBlockAlign, wfx->wBitsPerSample);
883 copy_waveformat(&This->format.Format, wfx);
885 freq = This->format.Format.nSamplesPerSec;
886 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
887 getALCError(This->parent->device);
889 This->format.Format.nSamplesPerSec = freq;
890 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
891 This->format.Format.nSamplesPerSec;
893 if(This->write_emu)
895 DS8Buffer *buf;
896 DSBUFFERDESC desc;
898 memset(&desc, 0, sizeof(desc));
899 desc.dwSize = sizeof(desc);
900 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
901 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
902 desc.lpwfxFormat = &This->format.Format;
904 hr = DS8Buffer_Create(&buf, This, NULL);
905 if(FAILED(hr))
906 goto out;
908 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, (IDirectSound*)&This->parent->IDirectSound8_iface, &desc);
909 if(FAILED(hr))
910 DS8Buffer_Destroy(buf);
911 else
913 IDirectSoundBuffer8_Release(This->write_emu);
914 This->write_emu = &buf->IDirectSoundBuffer8_iface;
918 out:
919 LeaveCriticalSection(&This->crst);
920 return hr;
923 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
925 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
926 HRESULT hr = S_OK;
928 TRACE("(%p)->(%d)\n", iface, vol);
930 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
932 WARN("Invalid volume (%d)\n", vol);
933 return DSERR_INVALIDPARAM;
936 EnterCriticalSection(&This->crst);
937 if(!(This->flags&DSBCAPS_CTRLVOLUME))
938 hr = DSERR_CONTROLUNAVAIL;
939 if(SUCCEEDED(hr))
941 setALContext(This->ctx);
942 alListenerf(AL_GAIN, mB_to_gain(vol));
943 popALContext();
945 LeaveCriticalSection(&This->crst);
947 return hr;
950 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
952 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
953 HRESULT hr;
955 TRACE("(%p)->(%d)\n", iface, pan);
957 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
959 WARN("invalid parameter: pan = %d\n", pan);
960 return DSERR_INVALIDPARAM;
963 EnterCriticalSection(&This->crst);
964 if(!(This->flags&DSBCAPS_CTRLPAN))
966 WARN("control unavailable\n");
967 hr = DSERR_CONTROLUNAVAIL;
969 else if(This->write_emu)
970 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
971 else
973 FIXME("Not supported\n");
974 hr = E_NOTIMPL;
976 LeaveCriticalSection(&This->crst);
978 return hr;
981 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
983 WARN("(%p)->(%u)\n", iface, freq);
984 return DSERR_CONTROLUNAVAIL;
987 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
989 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
990 HRESULT hr = S_OK;
992 TRACE("(%p)->()\n", iface);
994 EnterCriticalSection(&This->crst);
995 if(This->write_emu)
996 hr = IDirectSoundBuffer8_Stop(This->write_emu);
997 if(SUCCEEDED(hr))
998 This->stopped = TRUE;
999 LeaveCriticalSection(&This->crst);
1001 return hr;
1004 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1006 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1007 HRESULT hr = DSERR_INVALIDCALL;
1009 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1011 EnterCriticalSection(&This->crst);
1012 if(This->write_emu)
1013 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1014 LeaveCriticalSection(&This->crst);
1016 return hr;
1019 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1021 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1022 HRESULT hr = S_OK;
1024 TRACE("(%p)->()\n", iface);
1026 EnterCriticalSection(&This->crst);
1027 if(This->write_emu)
1028 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1029 LeaveCriticalSection(&This->crst);
1031 return hr;
1034 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1036 DS8Primary_QueryInterface,
1037 DS8Primary_AddRef,
1038 DS8Primary_Release,
1039 DS8Primary_GetCaps,
1040 DS8Primary_GetCurrentPosition,
1041 DS8Primary_GetFormat,
1042 DS8Primary_GetVolume,
1043 DS8Primary_GetPan,
1044 DS8Primary_GetFrequency,
1045 DS8Primary_GetStatus,
1046 DS8Primary_Initialize,
1047 DS8Primary_Lock,
1048 DS8Primary_Play,
1049 DS8Primary_SetCurrentPosition,
1050 DS8Primary_SetFormat,
1051 DS8Primary_SetVolume,
1052 DS8Primary_SetPan,
1053 DS8Primary_SetFrequency,
1054 DS8Primary_Stop,
1055 DS8Primary_Unlock,
1056 DS8Primary_Restore
1059 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
1061 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
1064 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1066 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1067 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1070 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1072 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1073 LONG ret;
1075 ret = InterlockedIncrement(&This->ds3d_ref);
1076 TRACE("new refcount %d\n", ret);
1078 return ret;
1082 /* Considering the primary buffer doesn't get destroyed
1083 * it doesn't make sense to destroy ds3d here
1085 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1087 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1088 LONG ret;
1090 ret = InterlockedDecrement(&This->ds3d_ref);
1091 TRACE("new refcount %d\n", ret);
1093 return ret;
1097 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1099 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1100 // HRESULT hr;
1102 TRACE("(%p)->(%p)\n", iface, listener);
1104 if(!listener || listener->dwSize < sizeof(*listener))
1106 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
1107 return DSERR_INVALIDPARAM;
1110 EnterCriticalSection(&This->crst);
1111 setALContext(This->ctx);
1112 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1113 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1114 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1115 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1116 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1117 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1118 popALContext();
1119 LeaveCriticalSection(&This->crst);
1121 // return hr;
1122 return DS_OK;
1125 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1127 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1129 TRACE("(%p)->(%p)\n", iface, distancefactor);
1131 if(!distancefactor)
1133 WARN("Invalid parameter %p\n", distancefactor);
1134 return DSERR_INVALIDPARAM;
1137 EnterCriticalSection(&This->crst);
1138 setALContext(This->ctx);
1140 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1141 getALError();
1143 popALContext();
1144 LeaveCriticalSection(&This->crst);
1146 return S_OK;
1149 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1151 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1153 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1155 if(!dopplerfactor)
1157 WARN("Invalid parameter %p\n", dopplerfactor);
1158 return DSERR_INVALIDPARAM;
1161 EnterCriticalSection(&This->crst);
1162 setALContext(This->ctx);
1164 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1165 getALError();
1167 popALContext();
1168 LeaveCriticalSection(&This->crst);
1170 return S_OK;
1173 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1175 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1176 ALfloat orient[6];
1178 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1180 if(!front || !top)
1182 WARN("Invalid parameter %p %p\n", front, top);
1183 return DSERR_INVALIDPARAM;
1186 EnterCriticalSection(&This->crst);
1187 setALContext(This->ctx);
1189 alGetListenerfv(AL_ORIENTATION, orient);
1190 getALError();
1192 front->x = orient[0];
1193 front->y = orient[1];
1194 front->z = -orient[2];
1195 top->x = orient[3];
1196 top->y = orient[4];
1197 top->z = -orient[5];
1199 popALContext();
1200 LeaveCriticalSection(&This->crst);
1202 return S_OK;
1205 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1207 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1208 ALfloat alpos[3];
1210 TRACE("(%p)->(%p)\n", iface, pos);
1212 if(!pos)
1214 WARN("Invalid parameter %p\n", pos);
1215 return DSERR_INVALIDPARAM;
1218 EnterCriticalSection(&This->crst);
1219 setALContext(This->ctx);
1221 alGetListenerfv(AL_POSITION, alpos);
1222 getALError();
1224 pos->x = alpos[0];
1225 pos->y = alpos[1];
1226 pos->z = -alpos[2];
1228 popALContext();
1229 LeaveCriticalSection(&This->crst);
1231 return S_OK;
1234 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1236 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1238 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1240 if(!rollofffactor)
1242 WARN("Invalid parameter %p\n", rollofffactor);
1243 return DSERR_INVALIDPARAM;
1246 EnterCriticalSection(&This->crst);
1247 *rollofffactor = This->rollofffactor;
1248 LeaveCriticalSection(&This->crst);
1250 return S_OK;
1253 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1255 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1256 ALfloat vel[3];
1258 TRACE("(%p)->(%p)\n", iface, velocity);
1260 if(!velocity)
1262 WARN("Invalid parameter %p\n", velocity);
1263 return DSERR_INVALIDPARAM;
1266 EnterCriticalSection(&This->crst);
1267 setALContext(This->ctx);
1269 alGetListenerfv(AL_VELOCITY, vel);
1270 getALError();
1272 velocity->x = vel[0];
1273 velocity->y = vel[1];
1274 velocity->z = -vel[2];
1276 popALContext();
1277 LeaveCriticalSection(&This->crst);
1279 return S_OK;
1282 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1284 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1286 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1288 if(!listen || listen->dwSize < sizeof(*listen))
1290 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1291 return DSERR_INVALIDPARAM;
1294 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1295 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1297 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1298 return DSERR_INVALIDPARAM;
1301 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1302 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1304 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1305 return DSERR_INVALIDPARAM;
1308 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1309 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1311 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1312 return DSERR_INVALIDPARAM;
1315 EnterCriticalSection(&This->crst);
1316 setALContext(This->ctx);
1317 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1318 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1319 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1320 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1321 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1322 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1323 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1324 popALContext();
1325 LeaveCriticalSection(&This->crst);
1327 return S_OK;
1330 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1332 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1334 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1336 if(factor < DS3D_MINDISTANCEFACTOR ||
1337 factor > DS3D_MAXDISTANCEFACTOR)
1339 WARN("Invalid parameter %f\n", factor);
1340 return DSERR_INVALIDPARAM;
1343 EnterCriticalSection(&This->crst);
1344 if(apply == DS3D_DEFERRED)
1346 This->listen.flDistanceFactor = factor;
1347 This->dirty.bit.distancefactor = 1;
1349 else
1351 setALContext(This->ctx);
1352 alSpeedOfSound(343.3f/factor);
1353 if(This->SupportedExt[EXT_EFX])
1354 alListenerf(AL_METERS_PER_UNIT, factor);
1355 getALError();
1356 popALContext();
1358 LeaveCriticalSection(&This->crst);
1360 return S_OK;
1363 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1365 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1367 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1369 if(factor < DS3D_MINDOPPLERFACTOR ||
1370 factor > DS3D_MAXDOPPLERFACTOR)
1372 WARN("Invalid parameter %f\n", factor);
1373 return DSERR_INVALIDPARAM;
1376 EnterCriticalSection(&This->crst);
1377 if(apply == DS3D_DEFERRED)
1379 This->listen.flDopplerFactor = factor;
1380 This->dirty.bit.dopplerfactor = 1;
1382 else
1384 setALContext(This->ctx);
1385 alDopplerFactor(factor);
1386 getALError();
1387 popALContext();
1389 LeaveCriticalSection(&This->crst);
1391 return S_OK;
1394 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1396 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1398 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1400 EnterCriticalSection(&This->crst);
1401 if(apply == DS3D_DEFERRED)
1403 This->listen.vOrientFront.x = xFront;
1404 This->listen.vOrientFront.y = yFront;
1405 This->listen.vOrientFront.z = zFront;
1406 This->listen.vOrientTop.x = xTop;
1407 This->listen.vOrientTop.y = yTop;
1408 This->listen.vOrientTop.z = zTop;
1409 This->dirty.bit.orientation = 1;
1411 else
1413 ALfloat orient[6] = {
1414 xFront, yFront, -zFront,
1415 xTop, yTop, -zTop
1417 setALContext(This->ctx);
1418 alListenerfv(AL_ORIENTATION, orient);
1419 getALError();
1420 popALContext();
1422 LeaveCriticalSection(&This->crst);
1424 return S_OK;
1427 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1429 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1431 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1433 EnterCriticalSection(&This->crst);
1434 if(apply == DS3D_DEFERRED)
1436 This->listen.vPosition.x = x;
1437 This->listen.vPosition.y = y;
1438 This->listen.vPosition.z = z;
1439 This->dirty.bit.pos = 1;
1441 else
1443 setALContext(This->ctx);
1444 alListener3f(AL_POSITION, x, y, -z);
1445 getALError();
1446 popALContext();
1448 LeaveCriticalSection(&This->crst);
1450 return S_OK;
1453 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1455 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1457 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1459 if(factor < DS3D_MINROLLOFFFACTOR ||
1460 factor > DS3D_MAXROLLOFFFACTOR)
1462 WARN("Invalid parameter %f\n", factor);
1463 return DSERR_INVALIDPARAM;
1466 EnterCriticalSection(&This->crst);
1467 if(apply == DS3D_DEFERRED)
1469 This->listen.flRolloffFactor = factor;
1470 This->dirty.bit.rollofffactor = 1;
1472 else
1474 DWORD i;
1476 setALContext(This->ctx);
1477 for(i = 0;i < This->nbuffers;++i)
1479 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1480 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1482 getALError();
1483 popALContext();
1485 This->rollofffactor = factor;
1487 LeaveCriticalSection(&This->crst);
1489 return S_OK;
1492 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1494 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1496 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1498 EnterCriticalSection(&This->crst);
1499 if(apply == DS3D_DEFERRED)
1501 This->listen.vVelocity.x = x;
1502 This->listen.vVelocity.y = y;
1503 This->listen.vVelocity.z = z;
1504 This->dirty.bit.vel = 1;
1506 else
1508 setALContext(This->ctx);
1509 alListener3f(AL_VELOCITY, x, y, -z);
1510 getALError();
1511 popALContext();
1513 LeaveCriticalSection(&This->crst);
1515 return S_OK;
1518 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1520 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1521 const DS3DLISTENER *listen = &This->listen;
1522 DWORD i;
1524 EnterCriticalSection(&This->crst);
1525 setALContext(This->ctx);
1526 This->ExtAL.DeferUpdates();
1528 if(This->dirty.bit.pos)
1529 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1530 if(This->dirty.bit.vel)
1531 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1532 if(This->dirty.bit.orientation)
1534 ALfloat orient[6] = {
1535 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1536 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1538 alListenerfv(AL_ORIENTATION, orient);
1540 if(This->dirty.bit.distancefactor)
1542 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1543 if(This->SupportedExt[EXT_EFX])
1544 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1547 if(This->dirty.bit.rollofffactor)
1549 ALfloat rolloff = This->rollofffactor;
1550 for(i = 0;i < This->nbuffers;++i)
1552 DS8Buffer *buf = This->buffers[i];
1553 if(buf->ds3dmode != DS3DMODE_DISABLE)
1554 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1558 if(This->dirty.bit.dopplerfactor)
1559 alDopplerFactor(listen->flDopplerFactor);
1561 if(This->dirty.bit.effect)
1562 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1564 /* getALError is here for debugging */
1565 getALError();
1567 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1568 This->dirty.flags = 0;
1570 for(i = 0;i < This->nbuffers;++i)
1572 DS8Buffer *buf = This->buffers[i];
1574 if(!buf->dirty.flags)
1575 continue;
1577 if(buf->dirty.bit.pos)
1578 alSource3f(buf->source, AL_POSITION,
1579 buf->ds3dbuffer.vPosition.x,
1580 buf->ds3dbuffer.vPosition.y,
1581 -buf->ds3dbuffer.vPosition.z);
1582 if(buf->dirty.bit.vel)
1583 alSource3f(buf->source, AL_VELOCITY,
1584 buf->ds3dbuffer.vVelocity.x,
1585 buf->ds3dbuffer.vVelocity.y,
1586 -buf->ds3dbuffer.vVelocity.z);
1587 if(buf->dirty.bit.cone_angles)
1589 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1590 buf->ds3dbuffer.dwInsideConeAngle);
1591 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1592 buf->ds3dbuffer.dwOutsideConeAngle);
1594 if(buf->dirty.bit.cone_orient)
1595 alSource3f(buf->source, AL_DIRECTION,
1596 buf->ds3dbuffer.vConeOrientation.x,
1597 buf->ds3dbuffer.vConeOrientation.y,
1598 -buf->ds3dbuffer.vConeOrientation.z);
1599 if(buf->dirty.bit.cone_outsidevolume)
1600 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1601 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1602 if(buf->dirty.bit.min_distance)
1603 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1604 if(buf->dirty.bit.max_distance)
1605 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1606 if(buf->dirty.bit.mode)
1608 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1609 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1610 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1611 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1612 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1614 buf->dirty.flags = 0;
1616 getALError();
1618 This->ExtAL.ProcessUpdates();
1619 popALContext();
1620 LeaveCriticalSection(&This->crst);
1622 return S_OK;
1625 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1627 DS8Primary3D_QueryInterface,
1628 DS8Primary3D_AddRef,
1629 DS8Primary3D_Release,
1630 DS8Primary3D_GetAllParameters,
1631 DS8Primary3D_GetDistanceFactor,
1632 DS8Primary3D_GetDopplerFactor,
1633 DS8Primary3D_GetOrientation,
1634 DS8Primary3D_GetPosition,
1635 DS8Primary3D_GetRolloffFactor,
1636 DS8Primary3D_GetVelocity,
1637 DS8Primary3D_SetAllParameters,
1638 DS8Primary3D_SetDistanceFactor,
1639 DS8Primary3D_SetDopplerFactor,
1640 DS8Primary3D_SetOrientation,
1641 DS8Primary3D_SetPosition,
1642 DS8Primary3D_SetRolloffFactor,
1643 DS8Primary3D_SetVelocity,
1644 DS8Primary3D_CommitDeferredSettings
1647 /* NOTE: Although the app handles listener properties through secondary buffers,
1648 * we pass the requests to the primary buffer though a propertyset interface.
1649 * These methods are not exposed to the app. */
1650 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1652 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1655 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1657 DS8Primary *This = impl_from_IKsPropertySet(iface);
1658 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1661 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1663 DS8Primary *This = impl_from_IKsPropertySet(iface);
1664 LONG ret;
1666 ret = InterlockedIncrement(&This->prop_ref);
1667 TRACE("new refcount %d\n", ret);
1669 return ret;
1672 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1674 DS8Primary *This = impl_from_IKsPropertySet(iface);
1675 LONG ret;
1677 ret = InterlockedDecrement(&This->prop_ref);
1678 TRACE("new refcount %d\n", ret);
1680 return ret;
1683 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1684 REFGUID guidPropSet, ULONG dwPropID,
1685 LPVOID pInstanceData, ULONG cbInstanceData,
1686 LPVOID pPropData, ULONG cbPropData,
1687 PULONG pcbReturned)
1689 DS8Primary *This = impl_from_IKsPropertySet(iface);
1690 HRESULT res = E_PROP_ID_UNSUPPORTED;
1692 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1693 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1695 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1697 EnterCriticalSection(&This->crst);
1699 if(This->effect == 0)
1700 res = E_PROP_ID_UNSUPPORTED;
1701 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1703 res = DSERR_INVALIDPARAM;
1704 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1706 union {
1707 void *v;
1708 EAXLISTENERPROPERTIES *props;
1709 } data = { pPropData };
1711 *data.props = This->eax_prop;
1712 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1713 res = DS_OK;
1716 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1718 res = DSERR_INVALIDPARAM;
1719 if(cbPropData >= sizeof(LONG))
1721 union {
1722 void *v;
1723 LONG *l;
1724 } data = { pPropData };
1726 *data.l = This->eax_prop.lRoom;
1727 *pcbReturned = sizeof(LONG);
1728 res = DS_OK;
1731 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1733 res = DSERR_INVALIDPARAM;
1734 if(cbPropData >= sizeof(LONG))
1736 union {
1737 void *v;
1738 LONG *l;
1739 } data = { pPropData };
1741 *data.l = This->eax_prop.lRoomHF;
1742 *pcbReturned = sizeof(LONG);
1743 res = DS_OK;
1746 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1748 res = DSERR_INVALIDPARAM;
1749 if(cbPropData >= sizeof(FLOAT))
1751 union {
1752 void *v;
1753 FLOAT *fl;
1754 } data = { pPropData };
1756 *data.fl = This->eax_prop.flRoomRolloffFactor;
1757 *pcbReturned = sizeof(FLOAT);
1758 res = DS_OK;
1761 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1763 res = DSERR_INVALIDPARAM;
1764 if(cbPropData >= sizeof(DWORD))
1766 union {
1767 void *v;
1768 DWORD *dw;
1769 } data = { pPropData };
1771 *data.dw = This->eax_prop.dwEnvironment;
1772 *pcbReturned = sizeof(DWORD);
1773 res = DS_OK;
1776 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1778 res = DSERR_INVALIDPARAM;
1779 if(cbPropData >= sizeof(FLOAT))
1781 union {
1782 void *v;
1783 FLOAT *fl;
1784 } data = { pPropData };
1786 *data.fl = This->eax_prop.flEnvironmentSize;
1787 *pcbReturned = sizeof(FLOAT);
1788 res = DS_OK;
1791 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1793 res = DSERR_INVALIDPARAM;
1794 if(cbPropData >= sizeof(FLOAT))
1796 union {
1797 void *v;
1798 FLOAT *fl;
1799 } data = { pPropData };
1801 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1802 *pcbReturned = sizeof(FLOAT);
1803 res = DS_OK;
1806 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1808 res = DSERR_INVALIDPARAM;
1809 if(cbPropData >= sizeof(FLOAT))
1811 union {
1812 void *v;
1813 FLOAT *fl;
1814 } data = { pPropData };
1816 *data.fl = This->eax_prop.flAirAbsorptionHF;
1817 *pcbReturned = sizeof(FLOAT);
1818 res = DS_OK;
1821 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1823 res = DSERR_INVALIDPARAM;
1824 if(cbPropData >= sizeof(DWORD))
1826 union {
1827 void *v;
1828 DWORD *dw;
1829 } data = { pPropData };
1831 *data.dw = This->eax_prop.dwFlags;
1832 *pcbReturned = sizeof(DWORD);
1833 res = DS_OK;
1836 else
1837 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1839 LeaveCriticalSection(&This->crst);
1841 else
1842 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1844 return res;
1847 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1848 REFGUID guidPropSet, ULONG dwPropID,
1849 LPVOID pInstanceData, ULONG cbInstanceData,
1850 LPVOID pPropData, ULONG cbPropData)
1852 DS8Primary *This = impl_from_IKsPropertySet(iface);
1853 HRESULT res = E_PROP_ID_UNSUPPORTED;
1855 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1856 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1858 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1860 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1861 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1863 EnterCriticalSection(&This->crst);
1864 setALContext(This->ctx);
1866 if(This->effect == 0)
1867 res = E_PROP_ID_UNSUPPORTED;
1868 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1870 do_allparams:
1871 res = DSERR_INVALIDPARAM;
1872 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1874 union {
1875 const void *v;
1876 const EAXLISTENERPROPERTIES *props;
1877 } data = { pPropData };
1879 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1880 This->eax_prop = *data.props;
1881 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1882 (data.props->flEnvironmentSize < 2.0f) ?
1883 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1884 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1885 data.props->flEnvironmentDiffusion);
1887 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1888 mB_to_gain(data.props->lRoom));
1889 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1890 mB_to_gain(data.props->lRoomHF));
1892 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1893 data.props->flRoomRolloffFactor);
1895 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1896 data.props->flDecayTime);
1897 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1898 data.props->flDecayHFRatio);
1900 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1901 mB_to_gain(data.props->lReflections));
1902 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1903 data.props->flReflectionsDelay);
1905 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1906 mB_to_gain(data.props->lReverb));
1907 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1908 data.props->flReverbDelay);
1910 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1911 mB_to_gain(data.props->flAirAbsorptionHF));
1913 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1914 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1915 AL_TRUE : AL_FALSE);
1917 getALError();
1919 This->dirty.bit.effect = 1;
1920 res = DS_OK;
1923 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1925 res = DSERR_INVALIDPARAM;
1926 if(cbPropData >= sizeof(LONG))
1928 union {
1929 const void *v;
1930 const LONG *l;
1931 } data = { pPropData };
1933 This->eax_prop.lRoom = *data.l;
1934 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1935 mB_to_gain(This->eax_prop.lRoom));
1936 getALError();
1938 This->dirty.bit.effect = 1;
1939 res = DS_OK;
1942 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1944 res = DSERR_INVALIDPARAM;
1945 if(cbPropData >= sizeof(LONG))
1947 union {
1948 const void *v;
1949 const LONG *l;
1950 } data = { pPropData };
1952 This->eax_prop.lRoomHF = *data.l;
1953 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1954 mB_to_gain(This->eax_prop.lRoomHF));
1955 getALError();
1957 This->dirty.bit.effect = 1;
1958 res = DS_OK;
1961 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1963 res = DSERR_INVALIDPARAM;
1964 if(cbPropData >= sizeof(FLOAT))
1966 union {
1967 const void *v;
1968 const FLOAT *fl;
1969 } data = { pPropData };
1971 This->eax_prop.flRoomRolloffFactor = *data.fl;
1972 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1973 This->eax_prop.flRoomRolloffFactor);
1974 getALError();
1976 This->dirty.bit.effect = 1;
1977 res = DS_OK;
1980 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1982 res = DSERR_INVALIDPARAM;
1983 if(cbPropData >= sizeof(DWORD))
1985 union {
1986 const void *v;
1987 const DWORD *dw;
1988 } data = { pPropData };
1990 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1992 /* Get the environment index's default and pass it down to
1993 * ALLPARAMETERS */
1994 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1995 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1996 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1997 goto do_allparams;
2001 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
2003 res = DSERR_INVALIDPARAM;
2004 if(cbPropData >= sizeof(FLOAT))
2006 union {
2007 const void *v;
2008 const FLOAT *fl;
2009 } data = { pPropData };
2011 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2013 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2015 This->eax_prop.flEnvironmentSize = *data.fl;
2017 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2019 This->eax_prop.flDecayTime *= scale;
2020 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2022 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2024 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2025 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2027 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2029 This->eax_prop.flReflectionsDelay *= scale;
2030 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2032 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2034 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2035 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2037 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2039 This->eax_prop.flReverbDelay *= scale;
2040 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2043 /* Pass the updated environment properties down to ALLPARAMETERS */
2044 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2045 pPropData = (void*)&This->eax_prop;
2046 cbPropData = sizeof(This->eax_prop);
2047 goto do_allparams;
2051 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
2053 res = DSERR_INVALIDPARAM;
2054 if(cbPropData >= sizeof(FLOAT))
2056 union {
2057 const void *v;
2058 const FLOAT *fl;
2059 } data = { pPropData };
2061 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2062 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2063 This->eax_prop.flEnvironmentDiffusion);
2064 getALError();
2066 This->dirty.bit.effect = 1;
2067 res = DS_OK;
2070 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
2072 res = DSERR_INVALIDPARAM;
2073 if(cbPropData >= sizeof(FLOAT))
2075 union {
2076 const void *v;
2077 const FLOAT *fl;
2078 } data = { pPropData };
2080 This->eax_prop.flAirAbsorptionHF = *data.fl;
2081 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2082 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2083 getALError();
2085 This->dirty.bit.effect = 1;
2086 res = DS_OK;
2089 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
2091 res = DSERR_INVALIDPARAM;
2092 if(cbPropData >= sizeof(DWORD))
2094 union {
2095 const void *v;
2096 const DWORD *dw;
2097 } data = { pPropData };
2099 This->eax_prop.dwFlags = *data.dw;
2100 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2101 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2102 AL_TRUE : AL_FALSE);
2103 getALError();
2105 This->dirty.bit.effect = 1;
2106 res = DS_OK;
2109 else if(propid != 0)
2110 FIXME("Unhandled propid: 0x%08x\n", propid);
2112 if(res == DS_OK && immediate)
2113 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2115 popALContext();
2116 LeaveCriticalSection(&This->crst);
2118 else
2119 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2121 return res;
2124 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2125 REFGUID guidPropSet, ULONG dwPropID,
2126 PULONG pTypeSupport)
2128 DS8Primary *This = impl_from_IKsPropertySet(iface);
2129 HRESULT res = E_PROP_ID_UNSUPPORTED;
2131 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2133 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2135 EnterCriticalSection(&This->crst);
2137 if(This->effect == 0)
2138 res = E_PROP_ID_UNSUPPORTED;
2139 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2140 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2141 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2142 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2143 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2144 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2145 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2146 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2147 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2149 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2150 res = DS_OK;
2152 else
2153 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
2155 LeaveCriticalSection(&This->crst);
2157 else
2158 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2160 return res;
2163 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2165 DS8PrimaryProp_QueryInterface,
2166 DS8PrimaryProp_AddRef,
2167 DS8PrimaryProp_Release,
2168 DS8PrimaryProp_Get,
2169 DS8PrimaryProp_Set,
2170 DS8PrimaryProp_QuerySupport