Remove unnecessary traces
[dsound-openal.git] / primary.c
blob20af266200ce6049f4d9875783389ef7061373d3
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->SupportedExt[SOFT_BUFFER_SAMPLES] &&
134 !prim->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
135 !prim->SupportedExt[EXT_STATIC_BUFFER])
137 for(i = 0;i < prim->nbuffers;++i)
139 DS8Buffer *buf = prim->buffers[i];
140 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
141 ALuint which, ofs;
143 if(buf->buffer->numsegs == 1 || !buf->isplaying)
144 continue;
146 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
147 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
148 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
150 queued -= done;
151 while(done--)
152 alSourceUnqueueBuffers(buf->source, 1, &which);
153 while(queued < QBUFFERS)
155 which = buf->buffer->buffers[buf->curidx];
156 ofs = buf->curidx*buf->buffer->segsize;
157 if(buf->curidx < buf->buffer->numsegs-1)
158 alBufferData(which, buf->buffer->buf_format,
159 buf->buffer->data + ofs, buf->buffer->segsize,
160 buf->buffer->format.Format.nSamplesPerSec);
161 else
162 alBufferData(which, buf->buffer->buf_format,
163 buf->buffer->data + ofs, buf->buffer->lastsegsize,
164 buf->buffer->format.Format.nSamplesPerSec);
166 alSourceQueueBuffers(buf->source, 1, &which);
167 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
168 queued++;
170 if(!buf->curidx && !buf->islooping)
172 buf->isplaying = FALSE;
173 break;
176 if(state != AL_PLAYING)
178 if(!queued)
180 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
181 continue;
183 alSourcePlay(buf->source);
185 getALError();
189 for(i = 0;i < prim->nnotifies;)
191 DS8Buffer *buf = prim->notifies[i];
192 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
193 DWORD status=0, curpos=buf->lastpos;
195 IDirectSoundBuffer8_GetStatus(dsb, &status);
196 IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
197 if(buf->lastpos != curpos)
199 trigger_elapsed_notifies(buf, buf->lastpos, curpos);
200 buf->lastpos = curpos;
202 if(!(status&DSBSTATUS_PLAYING))
204 /* Remove this buffer from list and put another at the
205 * current position; don't increment i
207 trigger_stop_notifies(buf);
208 prim->notifies[i] = prim->notifies[--prim->nnotifies];
209 continue;
211 i++;
213 popALContext();
214 LeaveCriticalSection(&prim->crst);
216 return 0;
220 HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
222 HRESULT hr = DSERR_OUTOFMEMORY;
223 DS8Primary *This = NULL;
224 DS3DLISTENER *listener;
225 WAVEFORMATEX *wfx;
226 ALuint srcs[256];
227 DWORD nsources;
229 *ppv = NULL;
230 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
231 if(!This) return hr;
233 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
234 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
235 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
237 InitializeCriticalSection(&This->crst);
238 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DS8Primary.crst");
240 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
241 wfx = &This->format.Format;
243 hr = DSERR_NODRIVER;
244 This->ctx = alcCreateContext(parent->device, NULL);
245 if(!This->ctx)
247 ALCenum err = alcGetError(parent->device);
248 ERR("Could not create context (0x%x)!\n", err);
249 goto fail;
252 setALContext(This->ctx);
253 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
255 TRACE("Found AL_EXT_FLOAT32\n");
256 This->SupportedExt[EXT_FLOAT32] = AL_TRUE;
258 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
260 TRACE("Found AL_EXT_MCFORMATS\n");
261 This->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
263 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
265 TRACE("Found AL_EXT_STATIC_BUFFER\n");
266 This->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
267 This->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
269 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
271 TRACE("Found AL_SOFTX_buffer_samples\n");
272 This->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
273 This->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
274 This->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
275 This->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
276 This->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
278 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
280 TRACE("Found AL_SOFT_buffer_sub_data\n");
281 This->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
282 This->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
284 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
286 TRACE("Found AL_SOFTX_deferred_updates\n");
287 This->ExtAL.DeferUpdates = alGetProcAddress("alDeferUpdatesSOFT");
288 This->ExtAL.ProcessUpdates = alGetProcAddress("alProcessUpdatesSOFT");
289 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
291 else
293 This->ExtAL.DeferUpdates = wrap_DeferUpdates;
294 This->ExtAL.ProcessUpdates = wrap_ProcessUpdates;
297 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
299 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
300 LOAD_FUNC(GenEffects);
301 LOAD_FUNC(DeleteEffects);
302 LOAD_FUNC(Effecti);
303 LOAD_FUNC(Effectf);
305 LOAD_FUNC(GenAuxiliaryEffectSlots);
306 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
307 LOAD_FUNC(AuxiliaryEffectSloti);
308 #undef LOAD_FUNC
309 This->SupportedExt[EXT_EFX] = AL_TRUE;
311 This->ExtAL.GenEffects(1, &This->effect);
312 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
314 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
316 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
318 wfx->wFormatTag = WAVE_FORMAT_PCM;
319 wfx->nChannels = 2;
320 wfx->wBitsPerSample = 8;
321 wfx->nSamplesPerSec = 22050;
322 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
323 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
324 wfx->cbSize = 0;
326 This->stopped = TRUE;
327 This->parent = parent;
328 /* Apparently primary buffer size is always 32k,
329 * tested on windows with 192k 24 bits sound @ 6 channels
330 * where it will run out in 60 ms and it isn't pointer aligned
332 This->buf_size = 32768;
334 if(!This->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
335 !This->SupportedExt[SOFT_BUFFER_SAMPLES] &&
336 !This->SupportedExt[EXT_STATIC_BUFFER])
338 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
339 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
340 ERR("Please consider using OpenAL-Soft\n");
343 /* Make sure DS3DListener defaults are applied to OpenAL */
344 listener = &This->listen;
345 listener->dwSize = sizeof(*listener);
346 listener->vPosition.x = 0.0;
347 listener->vPosition.y = 0.0;
348 listener->vPosition.z = 0.0;
349 listener->vVelocity.x = 0.0;
350 listener->vVelocity.y = 0.0;
351 listener->vVelocity.z = 0.0;
352 listener->vOrientFront.x = 0.0;
353 listener->vOrientFront.y = 0.0;
354 listener->vOrientFront.z = 1.0;
355 listener->vOrientTop.x = 0.0;
356 listener->vOrientTop.y = 1.0;
357 listener->vOrientTop.z = 0.0;
358 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
359 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
360 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
361 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
362 if(FAILED(hr))
363 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
365 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
367 alGenSources(1, &srcs[nsources]);
368 if(alGetError() != AL_NO_ERROR)
369 break;
371 alDeleteSources(nsources, srcs);
372 getALError();
374 popALContext();
376 This->max_sources = nsources;
377 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
379 hr = DSERR_OUTOFMEMORY;
380 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
381 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
382 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
383 if(!This->sources || !This->buffers || !This->notifies)
384 goto fail;
386 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
387 if(This->thread_hdl == NULL)
388 goto fail;
390 *ppv = This;
391 return S_OK;
393 fail:
394 DS8Primary_Destroy(This);
395 return hr;
398 void DS8Primary_Destroy(DS8Primary *This)
400 TRACE("Destroying primary %p\n", This);
402 if(This->timer_id)
404 timeKillEvent(This->timer_id);
405 timeEndPeriod(This->timer_res);
406 TRACE("Killed timer\n");
408 if(This->thread_hdl)
410 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
411 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
412 ERR("Thread wait timed out");
413 CloseHandle(This->thread_hdl);
416 if(This->ctx)
418 /* Calling setALContext is not appropriate here,
419 * since we *have* to unset the context before destroying it
421 ALCcontext *old_ctx;
423 EnterCriticalSection(&This->crst);
424 EnterCriticalSection(&openal_crst);
425 old_ctx = get_context();
426 if(old_ctx != This->ctx)
427 set_context(This->ctx);
428 else
429 old_ctx = NULL;
431 while(This->nbuffers--)
432 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
434 if(This->nsources)
435 alDeleteSources(This->nsources, This->sources);
437 if(This->effect)
438 This->ExtAL.DeleteEffects(1, &This->effect);
439 if(This->auxslot)
440 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
442 HeapFree(GetProcessHeap(), 0, This->sources);
443 HeapFree(GetProcessHeap(), 0, This->notifies);
444 HeapFree(GetProcessHeap(), 0, This->buffers);
446 set_context(old_ctx);
447 alcDestroyContext(This->ctx);
448 LeaveCriticalSection(&openal_crst);
449 LeaveCriticalSection(&This->crst);
452 This->crst.DebugInfo->Spare[0] = 0;
453 DeleteCriticalSection(&This->crst);
455 HeapFree(GetProcessHeap(), 0, This);
458 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
460 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
463 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
465 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
467 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
469 *ppv = NULL;
470 if(IsEqualIID(riid, &IID_IUnknown) ||
471 IsEqualIID(riid, &IID_IDirectSoundBuffer))
472 *ppv = &This->IDirectSoundBuffer_iface;
473 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
475 if((This->flags&DSBCAPS_CTRL3D))
476 *ppv = &This->IDirectSound3DListener_iface;
478 else
479 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
481 if(*ppv)
483 IUnknown_AddRef((IUnknown*)*ppv);
484 return S_OK;
487 return E_NOINTERFACE;
490 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
492 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
493 LONG ret;
495 ret = InterlockedIncrement(&This->ref);
496 if(ret == 1) This->flags = 0;
498 return ret;
501 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
503 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
504 LONG ret;
506 ret = InterlockedDecrement(&This->ref);
508 return ret;
511 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
513 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
515 TRACE("(%p)->(%p)\n", iface, caps);
517 if(!caps || caps->dwSize < sizeof(*caps))
519 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
520 return DSERR_INVALIDPARAM;
523 EnterCriticalSection(&This->crst);
524 caps->dwFlags = This->flags;
525 caps->dwBufferBytes = This->buf_size;
526 caps->dwUnlockTransferRate = 0;
527 caps->dwPlayCpuOverhead = 0;
528 LeaveCriticalSection(&This->crst);
530 return DS_OK;
533 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
535 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
536 HRESULT hr = DSERR_PRIOLEVELNEEDED;
538 EnterCriticalSection(&This->crst);
539 if(This->write_emu)
540 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
541 LeaveCriticalSection(&This->crst);
543 return hr;
546 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
548 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
549 HRESULT hr = S_OK;
550 UINT size;
552 if(!wfx && !written)
554 WARN("Cannot report format or format size\n");
555 return DSERR_INVALIDPARAM;
558 EnterCriticalSection(&This->crst);
559 size = sizeof(This->format.Format) + This->format.Format.cbSize;
560 if(written)
561 *written = size;
562 if(wfx)
564 if(allocated < size)
565 hr = DSERR_INVALIDPARAM;
566 else
567 memcpy(wfx, &This->format.Format, size);
569 LeaveCriticalSection(&This->crst);
571 return hr;
574 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
576 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
577 HRESULT hr = S_OK;
579 TRACE("(%p)->(%p)\n", iface, volume);
581 if(!volume)
582 return DSERR_INVALIDPARAM;
584 EnterCriticalSection(&This->crst);
585 if(!(This->flags & DSBCAPS_CTRLVOLUME))
586 hr = DSERR_CONTROLUNAVAIL;
587 else
589 ALfloat gain;
591 setALContext(This->ctx);
592 alGetListenerf(AL_GAIN, &gain);
593 getALError();
594 popALContext();
596 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
598 LeaveCriticalSection(&This->crst);
600 return hr;
603 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
605 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
606 HRESULT hr = S_OK;
608 WARN("(%p)->(%p): semi-stub\n", iface, pan);
610 if(!pan)
611 return DSERR_INVALIDPARAM;
613 EnterCriticalSection(&This->crst);
614 if(This->write_emu)
615 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
616 else if(!(This->flags & DSBCAPS_CTRLPAN))
617 hr = DSERR_CONTROLUNAVAIL;
618 else
619 *pan = 0;
620 LeaveCriticalSection(&This->crst);
622 return hr;
625 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
627 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
628 HRESULT hr = S_OK;
630 WARN("(%p)->(%p): semi-stub\n", iface, freq);
632 if(!freq)
633 return DSERR_INVALIDPARAM;
635 EnterCriticalSection(&This->crst);
636 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
637 hr = DSERR_CONTROLUNAVAIL;
638 else
639 *freq = This->format.Format.nSamplesPerSec;
640 LeaveCriticalSection(&This->crst);
642 return hr;
645 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
647 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
649 TRACE("(%p)->(%p)\n", iface, status);
651 if(!status)
652 return DSERR_INVALIDPARAM;
654 EnterCriticalSection(&This->crst);
656 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
657 if((This->flags&DSBCAPS_LOCDEFER))
658 *status |= DSBSTATUS_LOCHARDWARE;
660 if(This->stopped)
662 DWORD i, state;
663 HRESULT hr;
665 for(i = 0;i < This->nbuffers;++i)
667 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
668 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
669 break;
671 if(i == This->nbuffers)
673 /* Primary stopped and no buffers playing.. */
674 *status = 0;
678 LeaveCriticalSection(&This->crst);
680 return S_OK;
683 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
685 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
686 HRESULT hr = S_OK;
688 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
690 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
692 WARN("Bad DSBDESC for primary buffer\n");
693 return DSERR_INVALIDPARAM;
695 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
696 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
697 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
699 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
700 return DSERR_INVALIDPARAM;
703 EnterCriticalSection(&This->crst);
704 /* Should be 0 if not initialized */
705 if(This->flags)
707 hr = DSERR_ALREADYINITIALIZED;
708 goto out;
711 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
713 DSBUFFERDESC emudesc;
714 DS8Buffer *emu;
716 if(This->write_emu)
718 ERR("There shouldn't be a write_emu!\n");
719 IDirectSoundBuffer8_Release(This->write_emu);
720 This->write_emu = NULL;
723 memset(&emudesc, 0, sizeof(emudesc));
724 emudesc.dwSize = sizeof(emudesc);
725 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
726 /* Dont play last incomplete sample */
727 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
728 emudesc.lpwfxFormat = &This->format.Format;
730 hr = DS8Buffer_Create(&emu, This, NULL);
731 if(SUCCEEDED(hr))
733 This->write_emu = &emu->IDirectSoundBuffer8_iface;
734 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
735 if(FAILED(hr))
737 IDirectSoundBuffer8_Release(This->write_emu);
738 This->write_emu = NULL;
743 if(SUCCEEDED(hr))
744 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
745 out:
746 LeaveCriticalSection(&This->crst);
747 return hr;
750 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
752 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
753 HRESULT hr = DSERR_PRIOLEVELNEEDED;
755 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
757 EnterCriticalSection(&This->crst);
758 if(This->write_emu)
759 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
760 LeaveCriticalSection(&This->crst);
762 return hr;
765 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
767 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
768 HRESULT hr;
770 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
772 if(!(flags & DSBPLAY_LOOPING))
774 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
775 return DSERR_INVALIDPARAM;
778 EnterCriticalSection(&This->crst);
779 hr = S_OK;
780 if(This->write_emu)
781 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
782 if(SUCCEEDED(hr))
783 This->stopped = FALSE;
784 LeaveCriticalSection(&This->crst);
786 return hr;
789 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
791 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
792 return DSERR_INVALIDCALL;
795 /* Just assume the format is crap, and clean up the damage */
796 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
798 if(from->wFormatTag == WAVE_FORMAT_PCM)
800 wfx->cbSize = 0;
801 if(from->wBitsPerSample == 8 ||
802 from->wBitsPerSample == 16 ||
803 from->wBitsPerSample == 24 ||
804 from->wBitsPerSample == 32)
805 wfx->wBitsPerSample = from->wBitsPerSample;
807 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
809 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
810 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
811 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
813 /* Fail silently.. */
814 if(from->cbSize < size)
815 return;
816 if(!fromx->Samples.wValidBitsPerSample &&
817 !fromx->Format.wBitsPerSample)
818 return;
820 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
821 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
823 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
824 return;
827 wfe->Format.wBitsPerSample = from->wBitsPerSample;
828 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
829 if(!wfe->Samples.wValidBitsPerSample)
830 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
831 wfe->Format.cbSize = size;
832 wfe->dwChannelMask = fromx->dwChannelMask;
833 wfe->SubFormat = fromx->SubFormat;
835 else
837 ERR("Unhandled format tag %04x\n", from->wFormatTag);
838 return;
841 if(from->nChannels)
842 wfx->nChannels = from->nChannels;
843 wfx->wFormatTag = from->wFormatTag;
844 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
845 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
846 wfx->nSamplesPerSec = from->nSamplesPerSec;
847 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
848 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
851 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
853 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
854 HRESULT hr = S_OK;
855 ALCint freq;
857 TRACE("(%p)->(%p)\n", iface, wfx);
859 if(!wfx)
861 WARN("Missing format\n");
862 return DSERR_INVALIDPARAM;
865 EnterCriticalSection(&This->crst);
867 if(This->parent->prio_level < DSSCL_PRIORITY)
869 hr = DSERR_PRIOLEVELNEEDED;
870 goto out;
873 TRACE("Requested primary format:\n"
874 " FormatTag = %04x\n"
875 " Channels = %u\n"
876 " SamplesPerSec = %"LONGFMT"u\n"
877 " AvgBytesPerSec = %"LONGFMT"u\n"
878 " BlockAlign = %u\n"
879 " BitsPerSample = %u\n",
880 wfx->wFormatTag, wfx->nChannels,
881 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
882 wfx->nBlockAlign, wfx->wBitsPerSample);
884 copy_waveformat(&This->format.Format, wfx);
886 freq = This->format.Format.nSamplesPerSec;
887 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
888 getALCError(This->parent->device);
890 This->format.Format.nSamplesPerSec = freq;
891 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
892 This->format.Format.nSamplesPerSec;
894 if(This->write_emu)
896 DS8Buffer *buf;
897 DSBUFFERDESC desc;
899 memset(&desc, 0, sizeof(desc));
900 desc.dwSize = sizeof(desc);
901 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
902 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
903 desc.lpwfxFormat = &This->format.Format;
905 hr = DS8Buffer_Create(&buf, This, NULL);
906 if(FAILED(hr))
907 goto out;
909 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
910 if(FAILED(hr))
911 DS8Buffer_Destroy(buf);
912 else
914 IDirectSoundBuffer8_Release(This->write_emu);
915 This->write_emu = &buf->IDirectSoundBuffer8_iface;
919 out:
920 LeaveCriticalSection(&This->crst);
921 return hr;
924 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
926 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
927 HRESULT hr = S_OK;
929 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
931 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
933 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
934 return DSERR_INVALIDPARAM;
937 EnterCriticalSection(&This->crst);
938 if(!(This->flags&DSBCAPS_CTRLVOLUME))
939 hr = DSERR_CONTROLUNAVAIL;
940 if(SUCCEEDED(hr))
942 setALContext(This->ctx);
943 alListenerf(AL_GAIN, mB_to_gain(vol));
944 popALContext();
946 LeaveCriticalSection(&This->crst);
948 return hr;
951 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
953 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
954 HRESULT hr;
956 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
958 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
960 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
961 return DSERR_INVALIDPARAM;
964 EnterCriticalSection(&This->crst);
965 if(!(This->flags&DSBCAPS_CTRLPAN))
967 WARN("control unavailable\n");
968 hr = DSERR_CONTROLUNAVAIL;
970 else if(This->write_emu)
971 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
972 else
974 FIXME("Not supported\n");
975 hr = E_NOTIMPL;
977 LeaveCriticalSection(&This->crst);
979 return hr;
982 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
984 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
985 return DSERR_CONTROLUNAVAIL;
988 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
990 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
991 HRESULT hr = S_OK;
993 TRACE("(%p)->()\n", iface);
995 EnterCriticalSection(&This->crst);
996 if(This->write_emu)
997 hr = IDirectSoundBuffer8_Stop(This->write_emu);
998 if(SUCCEEDED(hr))
999 This->stopped = TRUE;
1000 LeaveCriticalSection(&This->crst);
1002 return hr;
1005 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1007 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1008 HRESULT hr = DSERR_INVALIDCALL;
1010 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
1012 EnterCriticalSection(&This->crst);
1013 if(This->write_emu)
1014 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1015 LeaveCriticalSection(&This->crst);
1017 return hr;
1020 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1022 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1023 HRESULT hr = S_OK;
1025 TRACE("(%p)->()\n", iface);
1027 EnterCriticalSection(&This->crst);
1028 if(This->write_emu)
1029 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1030 LeaveCriticalSection(&This->crst);
1032 return hr;
1035 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1037 DS8Primary_QueryInterface,
1038 DS8Primary_AddRef,
1039 DS8Primary_Release,
1040 DS8Primary_GetCaps,
1041 DS8Primary_GetCurrentPosition,
1042 DS8Primary_GetFormat,
1043 DS8Primary_GetVolume,
1044 DS8Primary_GetPan,
1045 DS8Primary_GetFrequency,
1046 DS8Primary_GetStatus,
1047 DS8Primary_Initialize,
1048 DS8Primary_Lock,
1049 DS8Primary_Play,
1050 DS8Primary_SetCurrentPosition,
1051 DS8Primary_SetFormat,
1052 DS8Primary_SetVolume,
1053 DS8Primary_SetPan,
1054 DS8Primary_SetFrequency,
1055 DS8Primary_Stop,
1056 DS8Primary_Unlock,
1057 DS8Primary_Restore
1060 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
1062 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
1065 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1067 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1068 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1071 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1073 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1074 LONG ret;
1076 ret = InterlockedIncrement(&This->ds3d_ref);
1077 TRACE("new refcount %"LONGFMT"d\n", ret);
1079 return ret;
1083 /* Considering the primary buffer doesn't get destroyed
1084 * it doesn't make sense to destroy ds3d here
1086 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1088 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1089 LONG ret;
1091 ret = InterlockedDecrement(&This->ds3d_ref);
1092 TRACE("new refcount %"LONGFMT"d\n", ret);
1094 return ret;
1098 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1100 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1102 TRACE("(%p)->(%p)\n", iface, listener);
1104 if(!listener || listener->dwSize < sizeof(*listener))
1106 WARN("Invalid DS3DLISTENER %p %"LONGFMT"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 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, %"LONGFMT"u)\n", iface, listen, apply);
1287 if(!listen || listen->dwSize < sizeof(*listen))
1289 WARN("Invalid parameter %p %"LONGFMT"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, %"LONGFMT"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, %"LONGFMT"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, %"LONGFMT"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, %"LONGFMT"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, %"LONGFMT"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, %"LONGFMT"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 DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, 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 %"LONGFMT"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 %"LONGFMT"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;
1690 (void)pInstanceData;
1691 (void)cbInstanceData;
1693 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1695 EnterCriticalSection(&This->crst);
1697 if(This->effect == 0)
1698 res = E_PROP_ID_UNSUPPORTED;
1699 else switch(dwPropID)
1701 case 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;
1714 break;
1716 case 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;
1729 break;
1730 case DSPROPERTY_EAXLISTENER_ROOMHF:
1731 res = DSERR_INVALIDPARAM;
1732 if(cbPropData >= sizeof(LONG))
1734 union {
1735 void *v;
1736 LONG *l;
1737 } data = { pPropData };
1739 *data.l = This->eax_prop.lRoomHF;
1740 *pcbReturned = sizeof(LONG);
1741 res = DS_OK;
1743 break;
1745 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1746 res = DSERR_INVALIDPARAM;
1747 if(cbPropData >= sizeof(FLOAT))
1749 union {
1750 void *v;
1751 FLOAT *fl;
1752 } data = { pPropData };
1754 *data.fl = This->eax_prop.flRoomRolloffFactor;
1755 *pcbReturned = sizeof(FLOAT);
1756 res = DS_OK;
1758 break;
1760 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1761 res = DSERR_INVALIDPARAM;
1762 if(cbPropData >= sizeof(DWORD))
1764 union {
1765 void *v;
1766 DWORD *dw;
1767 } data = { pPropData };
1769 *data.dw = This->eax_prop.dwEnvironment;
1770 *pcbReturned = sizeof(DWORD);
1771 res = DS_OK;
1773 break;
1775 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1776 res = DSERR_INVALIDPARAM;
1777 if(cbPropData >= sizeof(FLOAT))
1779 union {
1780 void *v;
1781 FLOAT *fl;
1782 } data = { pPropData };
1784 *data.fl = This->eax_prop.flEnvironmentSize;
1785 *pcbReturned = sizeof(FLOAT);
1786 res = DS_OK;
1788 break;
1789 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1790 res = DSERR_INVALIDPARAM;
1791 if(cbPropData >= sizeof(FLOAT))
1793 union {
1794 void *v;
1795 FLOAT *fl;
1796 } data = { pPropData };
1798 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1799 *pcbReturned = sizeof(FLOAT);
1800 res = DS_OK;
1802 break;
1804 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1805 res = DSERR_INVALIDPARAM;
1806 if(cbPropData >= sizeof(FLOAT))
1808 union {
1809 void *v;
1810 FLOAT *fl;
1811 } data = { pPropData };
1813 *data.fl = This->eax_prop.flAirAbsorptionHF;
1814 *pcbReturned = sizeof(FLOAT);
1815 res = DS_OK;
1817 break;
1819 case DSPROPERTY_EAXLISTENER_FLAGS:
1820 res = DSERR_INVALIDPARAM;
1821 if(cbPropData >= sizeof(DWORD))
1823 union {
1824 void *v;
1825 DWORD *dw;
1826 } data = { pPropData };
1828 *data.dw = This->eax_prop.dwFlags;
1829 *pcbReturned = sizeof(DWORD);
1830 res = DS_OK;
1832 break;
1834 default:
1835 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1836 break;
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;
1854 (void)pInstanceData;
1855 (void)cbInstanceData;
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 switch(propid)
1869 case 0: /* 0 = not setting any property, just apply */
1870 res = DS_OK;
1871 break;
1873 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1874 do_allparams:
1875 res = DSERR_INVALIDPARAM;
1876 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1878 union {
1879 const void *v;
1880 const EAXLISTENERPROPERTIES *props;
1881 } data = { pPropData };
1883 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1884 This->eax_prop = *data.props;
1885 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1886 (data.props->flEnvironmentSize < 2.0f) ?
1887 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1888 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1889 data.props->flEnvironmentDiffusion);
1891 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1892 mB_to_gain(data.props->lRoom));
1893 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1894 mB_to_gain(data.props->lRoomHF));
1896 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1897 data.props->flRoomRolloffFactor);
1899 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1900 data.props->flDecayTime);
1901 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1902 data.props->flDecayHFRatio);
1904 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1905 mB_to_gain(data.props->lReflections));
1906 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1907 data.props->flReflectionsDelay);
1909 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1910 mB_to_gain(data.props->lReverb));
1911 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1912 data.props->flReverbDelay);
1914 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1915 mB_to_gain(data.props->flAirAbsorptionHF));
1917 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1918 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1919 AL_TRUE : AL_FALSE);
1921 getALError();
1923 This->dirty.bit.effect = 1;
1924 res = DS_OK;
1926 break;
1928 case DSPROPERTY_EAXLISTENER_ROOM:
1929 res = DSERR_INVALIDPARAM;
1930 if(cbPropData >= sizeof(LONG))
1932 union {
1933 const void *v;
1934 const LONG *l;
1935 } data = { pPropData };
1937 This->eax_prop.lRoom = *data.l;
1938 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1939 mB_to_gain(This->eax_prop.lRoom));
1940 getALError();
1942 This->dirty.bit.effect = 1;
1943 res = DS_OK;
1945 break;
1946 case DSPROPERTY_EAXLISTENER_ROOMHF:
1947 res = DSERR_INVALIDPARAM;
1948 if(cbPropData >= sizeof(LONG))
1950 union {
1951 const void *v;
1952 const LONG *l;
1953 } data = { pPropData };
1955 This->eax_prop.lRoomHF = *data.l;
1956 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1957 mB_to_gain(This->eax_prop.lRoomHF));
1958 getALError();
1960 This->dirty.bit.effect = 1;
1961 res = DS_OK;
1963 break;
1965 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1966 res = DSERR_INVALIDPARAM;
1967 if(cbPropData >= sizeof(FLOAT))
1969 union {
1970 const void *v;
1971 const FLOAT *fl;
1972 } data = { pPropData };
1974 This->eax_prop.flRoomRolloffFactor = *data.fl;
1975 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1976 This->eax_prop.flRoomRolloffFactor);
1977 getALError();
1979 This->dirty.bit.effect = 1;
1980 res = DS_OK;
1982 break;
1984 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1985 res = DSERR_INVALIDPARAM;
1986 if(cbPropData >= sizeof(DWORD))
1988 union {
1989 const void *v;
1990 const DWORD *dw;
1991 } data = { pPropData };
1993 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1995 /* Get the environment index's default and pass it down to
1996 * ALLPARAMETERS */
1997 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1998 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1999 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
2000 goto do_allparams;
2003 break;
2005 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2006 res = DSERR_INVALIDPARAM;
2007 if(cbPropData >= sizeof(FLOAT))
2009 union {
2010 const void *v;
2011 const FLOAT *fl;
2012 } data = { pPropData };
2014 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2016 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2018 This->eax_prop.flEnvironmentSize = *data.fl;
2020 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2022 This->eax_prop.flDecayTime *= scale;
2023 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2025 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2027 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2028 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2030 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2032 This->eax_prop.flReflectionsDelay *= scale;
2033 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2035 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2037 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2038 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2040 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2042 This->eax_prop.flReverbDelay *= scale;
2043 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2046 /* Pass the updated environment properties down to ALLPARAMETERS */
2047 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2048 pPropData = (void*)&This->eax_prop;
2049 cbPropData = sizeof(This->eax_prop);
2050 goto do_allparams;
2053 break;
2054 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2055 res = DSERR_INVALIDPARAM;
2056 if(cbPropData >= sizeof(FLOAT))
2058 union {
2059 const void *v;
2060 const FLOAT *fl;
2061 } data = { pPropData };
2063 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2064 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2065 This->eax_prop.flEnvironmentDiffusion);
2066 getALError();
2068 This->dirty.bit.effect = 1;
2069 res = DS_OK;
2071 break;
2073 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2074 res = DSERR_INVALIDPARAM;
2075 if(cbPropData >= sizeof(FLOAT))
2077 union {
2078 const void *v;
2079 const FLOAT *fl;
2080 } data = { pPropData };
2082 This->eax_prop.flAirAbsorptionHF = *data.fl;
2083 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2084 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2085 getALError();
2087 This->dirty.bit.effect = 1;
2088 res = DS_OK;
2090 break;
2092 case DSPROPERTY_EAXLISTENER_FLAGS:
2093 res = DSERR_INVALIDPARAM;
2094 if(cbPropData >= sizeof(DWORD))
2096 union {
2097 const void *v;
2098 const DWORD *dw;
2099 } data = { pPropData };
2101 This->eax_prop.dwFlags = *data.dw;
2102 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2103 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2104 AL_TRUE : AL_FALSE);
2105 getALError();
2107 This->dirty.bit.effect = 1;
2108 res = DS_OK;
2110 default:
2111 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2112 break;
2115 if(res == DS_OK && immediate)
2116 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2118 popALContext();
2119 LeaveCriticalSection(&This->crst);
2121 else
2122 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2124 return res;
2127 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2128 REFGUID guidPropSet, ULONG dwPropID,
2129 PULONG pTypeSupport)
2131 DS8Primary *This = impl_from_IKsPropertySet(iface);
2132 HRESULT res = E_PROP_ID_UNSUPPORTED;
2134 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2136 EnterCriticalSection(&This->crst);
2138 if(This->effect == 0)
2139 res = E_PROP_ID_UNSUPPORTED;
2140 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2141 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2142 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2143 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2144 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2145 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2146 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2147 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2148 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2150 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2151 res = DS_OK;
2153 else
2154 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2156 LeaveCriticalSection(&This->crst);
2158 else
2159 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2161 return res;
2164 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2166 DS8PrimaryProp_QueryInterface,
2167 DS8PrimaryProp_AddRef,
2168 DS8PrimaryProp_Release,
2169 DS8PrimaryProp_Get,
2170 DS8PrimaryProp_Set,
2171 DS8PrimaryProp_QuerySupport