Minor cleanup for buffer creation
[dsound-openal.git] / primary.c
blob9f896fdf8b4acbd3ec90b677937aababa37a7b80
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: %08x\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, %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 = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &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 %08x\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)->(%u, %u, %p, %p, %p, %p, %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)->(%u, %u, %u)\n", iface, res1, res2, flags);
772 if(!(flags & DSBPLAY_LOOPING))
774 WARN("Flags (%08x) 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)->(%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 = %u\n"
877 " AvgBytesPerSec = %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, (IDirectSound*)&This->parent->IDirectSound8_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)->(%d)\n", iface, vol);
931 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
933 WARN("Invalid volume (%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)->(%d)\n", iface, pan);
958 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
960 WARN("invalid parameter: pan = %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)->(%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, %u, %p, %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 IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, 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 %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 %d\n", ret);
1094 return ret;
1098 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1100 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1101 // HRESULT hr;
1103 TRACE("(%p)->(%p)\n", iface, listener);
1105 if(!listener || listener->dwSize < sizeof(*listener))
1107 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
1108 return DSERR_INVALIDPARAM;
1111 EnterCriticalSection(&This->crst);
1112 setALContext(This->ctx);
1113 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1114 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1115 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1116 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1117 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1118 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1119 popALContext();
1120 LeaveCriticalSection(&This->crst);
1122 // return hr;
1123 return DS_OK;
1126 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1128 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1130 TRACE("(%p)->(%p)\n", iface, distancefactor);
1132 if(!distancefactor)
1134 WARN("Invalid parameter %p\n", distancefactor);
1135 return DSERR_INVALIDPARAM;
1138 EnterCriticalSection(&This->crst);
1139 setALContext(This->ctx);
1141 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1142 getALError();
1144 popALContext();
1145 LeaveCriticalSection(&This->crst);
1147 return S_OK;
1150 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1152 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1154 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1156 if(!dopplerfactor)
1158 WARN("Invalid parameter %p\n", dopplerfactor);
1159 return DSERR_INVALIDPARAM;
1162 EnterCriticalSection(&This->crst);
1163 setALContext(This->ctx);
1165 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1166 getALError();
1168 popALContext();
1169 LeaveCriticalSection(&This->crst);
1171 return S_OK;
1174 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1176 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1177 ALfloat orient[6];
1179 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1181 if(!front || !top)
1183 WARN("Invalid parameter %p %p\n", front, top);
1184 return DSERR_INVALIDPARAM;
1187 EnterCriticalSection(&This->crst);
1188 setALContext(This->ctx);
1190 alGetListenerfv(AL_ORIENTATION, orient);
1191 getALError();
1193 front->x = orient[0];
1194 front->y = orient[1];
1195 front->z = -orient[2];
1196 top->x = orient[3];
1197 top->y = orient[4];
1198 top->z = -orient[5];
1200 popALContext();
1201 LeaveCriticalSection(&This->crst);
1203 return S_OK;
1206 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1208 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1209 ALfloat alpos[3];
1211 TRACE("(%p)->(%p)\n", iface, pos);
1213 if(!pos)
1215 WARN("Invalid parameter %p\n", pos);
1216 return DSERR_INVALIDPARAM;
1219 EnterCriticalSection(&This->crst);
1220 setALContext(This->ctx);
1222 alGetListenerfv(AL_POSITION, alpos);
1223 getALError();
1225 pos->x = alpos[0];
1226 pos->y = alpos[1];
1227 pos->z = -alpos[2];
1229 popALContext();
1230 LeaveCriticalSection(&This->crst);
1232 return S_OK;
1235 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1237 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1239 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1241 if(!rollofffactor)
1243 WARN("Invalid parameter %p\n", rollofffactor);
1244 return DSERR_INVALIDPARAM;
1247 EnterCriticalSection(&This->crst);
1248 *rollofffactor = This->rollofffactor;
1249 LeaveCriticalSection(&This->crst);
1251 return S_OK;
1254 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1256 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1257 ALfloat vel[3];
1259 TRACE("(%p)->(%p)\n", iface, velocity);
1261 if(!velocity)
1263 WARN("Invalid parameter %p\n", velocity);
1264 return DSERR_INVALIDPARAM;
1267 EnterCriticalSection(&This->crst);
1268 setALContext(This->ctx);
1270 alGetListenerfv(AL_VELOCITY, vel);
1271 getALError();
1273 velocity->x = vel[0];
1274 velocity->y = vel[1];
1275 velocity->z = -vel[2];
1277 popALContext();
1278 LeaveCriticalSection(&This->crst);
1280 return S_OK;
1283 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1285 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1287 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1289 if(!listen || listen->dwSize < sizeof(*listen))
1291 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1292 return DSERR_INVALIDPARAM;
1295 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1296 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1298 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1299 return DSERR_INVALIDPARAM;
1302 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1303 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1305 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1306 return DSERR_INVALIDPARAM;
1309 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1310 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1312 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1313 return DSERR_INVALIDPARAM;
1316 EnterCriticalSection(&This->crst);
1317 setALContext(This->ctx);
1318 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1319 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1320 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1321 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1322 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1323 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1324 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1325 popALContext();
1326 LeaveCriticalSection(&This->crst);
1328 return S_OK;
1331 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1333 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1335 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1337 if(factor < DS3D_MINDISTANCEFACTOR ||
1338 factor > DS3D_MAXDISTANCEFACTOR)
1340 WARN("Invalid parameter %f\n", factor);
1341 return DSERR_INVALIDPARAM;
1344 EnterCriticalSection(&This->crst);
1345 if(apply == DS3D_DEFERRED)
1347 This->listen.flDistanceFactor = factor;
1348 This->dirty.bit.distancefactor = 1;
1350 else
1352 setALContext(This->ctx);
1353 alSpeedOfSound(343.3f/factor);
1354 if(This->SupportedExt[EXT_EFX])
1355 alListenerf(AL_METERS_PER_UNIT, factor);
1356 getALError();
1357 popALContext();
1359 LeaveCriticalSection(&This->crst);
1361 return S_OK;
1364 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1366 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1368 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1370 if(factor < DS3D_MINDOPPLERFACTOR ||
1371 factor > DS3D_MAXDOPPLERFACTOR)
1373 WARN("Invalid parameter %f\n", factor);
1374 return DSERR_INVALIDPARAM;
1377 EnterCriticalSection(&This->crst);
1378 if(apply == DS3D_DEFERRED)
1380 This->listen.flDopplerFactor = factor;
1381 This->dirty.bit.dopplerfactor = 1;
1383 else
1385 setALContext(This->ctx);
1386 alDopplerFactor(factor);
1387 getALError();
1388 popALContext();
1390 LeaveCriticalSection(&This->crst);
1392 return S_OK;
1395 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1397 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1399 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1401 EnterCriticalSection(&This->crst);
1402 if(apply == DS3D_DEFERRED)
1404 This->listen.vOrientFront.x = xFront;
1405 This->listen.vOrientFront.y = yFront;
1406 This->listen.vOrientFront.z = zFront;
1407 This->listen.vOrientTop.x = xTop;
1408 This->listen.vOrientTop.y = yTop;
1409 This->listen.vOrientTop.z = zTop;
1410 This->dirty.bit.orientation = 1;
1412 else
1414 ALfloat orient[6] = {
1415 xFront, yFront, -zFront,
1416 xTop, yTop, -zTop
1418 setALContext(This->ctx);
1419 alListenerfv(AL_ORIENTATION, orient);
1420 getALError();
1421 popALContext();
1423 LeaveCriticalSection(&This->crst);
1425 return S_OK;
1428 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1430 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1432 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1434 EnterCriticalSection(&This->crst);
1435 if(apply == DS3D_DEFERRED)
1437 This->listen.vPosition.x = x;
1438 This->listen.vPosition.y = y;
1439 This->listen.vPosition.z = z;
1440 This->dirty.bit.pos = 1;
1442 else
1444 setALContext(This->ctx);
1445 alListener3f(AL_POSITION, x, y, -z);
1446 getALError();
1447 popALContext();
1449 LeaveCriticalSection(&This->crst);
1451 return S_OK;
1454 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1456 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1458 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1460 if(factor < DS3D_MINROLLOFFFACTOR ||
1461 factor > DS3D_MAXROLLOFFFACTOR)
1463 WARN("Invalid parameter %f\n", factor);
1464 return DSERR_INVALIDPARAM;
1467 EnterCriticalSection(&This->crst);
1468 if(apply == DS3D_DEFERRED)
1470 This->listen.flRolloffFactor = factor;
1471 This->dirty.bit.rollofffactor = 1;
1473 else
1475 DWORD i;
1477 setALContext(This->ctx);
1478 for(i = 0;i < This->nbuffers;++i)
1480 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1481 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1483 getALError();
1484 popALContext();
1486 This->rollofffactor = factor;
1488 LeaveCriticalSection(&This->crst);
1490 return S_OK;
1493 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1495 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1497 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1499 EnterCriticalSection(&This->crst);
1500 if(apply == DS3D_DEFERRED)
1502 This->listen.vVelocity.x = x;
1503 This->listen.vVelocity.y = y;
1504 This->listen.vVelocity.z = z;
1505 This->dirty.bit.vel = 1;
1507 else
1509 setALContext(This->ctx);
1510 alListener3f(AL_VELOCITY, x, y, -z);
1511 getALError();
1512 popALContext();
1514 LeaveCriticalSection(&This->crst);
1516 return S_OK;
1519 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1521 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1522 const DS3DLISTENER *listen = &This->listen;
1523 DWORD i;
1525 EnterCriticalSection(&This->crst);
1526 setALContext(This->ctx);
1527 This->ExtAL.DeferUpdates();
1529 if(This->dirty.bit.pos)
1530 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1531 if(This->dirty.bit.vel)
1532 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1533 if(This->dirty.bit.orientation)
1535 ALfloat orient[6] = {
1536 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1537 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1539 alListenerfv(AL_ORIENTATION, orient);
1541 if(This->dirty.bit.distancefactor)
1543 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1544 if(This->SupportedExt[EXT_EFX])
1545 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1548 if(This->dirty.bit.rollofffactor)
1550 ALfloat rolloff = This->rollofffactor;
1551 for(i = 0;i < This->nbuffers;++i)
1553 DS8Buffer *buf = This->buffers[i];
1554 if(buf->ds3dmode != DS3DMODE_DISABLE)
1555 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1559 if(This->dirty.bit.dopplerfactor)
1560 alDopplerFactor(listen->flDopplerFactor);
1562 if(This->dirty.bit.effect)
1563 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1565 /* getALError is here for debugging */
1566 getALError();
1568 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1569 This->dirty.flags = 0;
1571 for(i = 0;i < This->nbuffers;++i)
1573 DS8Buffer *buf = This->buffers[i];
1575 if(!buf->dirty.flags)
1576 continue;
1578 if(buf->dirty.bit.pos)
1579 alSource3f(buf->source, AL_POSITION,
1580 buf->ds3dbuffer.vPosition.x,
1581 buf->ds3dbuffer.vPosition.y,
1582 -buf->ds3dbuffer.vPosition.z);
1583 if(buf->dirty.bit.vel)
1584 alSource3f(buf->source, AL_VELOCITY,
1585 buf->ds3dbuffer.vVelocity.x,
1586 buf->ds3dbuffer.vVelocity.y,
1587 -buf->ds3dbuffer.vVelocity.z);
1588 if(buf->dirty.bit.cone_angles)
1590 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1591 buf->ds3dbuffer.dwInsideConeAngle);
1592 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1593 buf->ds3dbuffer.dwOutsideConeAngle);
1595 if(buf->dirty.bit.cone_orient)
1596 alSource3f(buf->source, AL_DIRECTION,
1597 buf->ds3dbuffer.vConeOrientation.x,
1598 buf->ds3dbuffer.vConeOrientation.y,
1599 -buf->ds3dbuffer.vConeOrientation.z);
1600 if(buf->dirty.bit.cone_outsidevolume)
1601 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1602 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1603 if(buf->dirty.bit.min_distance)
1604 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1605 if(buf->dirty.bit.max_distance)
1606 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1607 if(buf->dirty.bit.mode)
1609 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1610 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1611 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1612 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1613 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1615 buf->dirty.flags = 0;
1617 getALError();
1619 This->ExtAL.ProcessUpdates();
1620 popALContext();
1621 LeaveCriticalSection(&This->crst);
1623 return S_OK;
1626 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1628 DS8Primary3D_QueryInterface,
1629 DS8Primary3D_AddRef,
1630 DS8Primary3D_Release,
1631 DS8Primary3D_GetAllParameters,
1632 DS8Primary3D_GetDistanceFactor,
1633 DS8Primary3D_GetDopplerFactor,
1634 DS8Primary3D_GetOrientation,
1635 DS8Primary3D_GetPosition,
1636 DS8Primary3D_GetRolloffFactor,
1637 DS8Primary3D_GetVelocity,
1638 DS8Primary3D_SetAllParameters,
1639 DS8Primary3D_SetDistanceFactor,
1640 DS8Primary3D_SetDopplerFactor,
1641 DS8Primary3D_SetOrientation,
1642 DS8Primary3D_SetPosition,
1643 DS8Primary3D_SetRolloffFactor,
1644 DS8Primary3D_SetVelocity,
1645 DS8Primary3D_CommitDeferredSettings
1648 /* NOTE: Although the app handles listener properties through secondary buffers,
1649 * we pass the requests to the primary buffer though a propertyset interface.
1650 * These methods are not exposed to the app. */
1651 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1653 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1656 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1658 DS8Primary *This = impl_from_IKsPropertySet(iface);
1659 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1662 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1664 DS8Primary *This = impl_from_IKsPropertySet(iface);
1665 LONG ret;
1667 ret = InterlockedIncrement(&This->prop_ref);
1668 TRACE("new refcount %d\n", ret);
1670 return ret;
1673 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1675 DS8Primary *This = impl_from_IKsPropertySet(iface);
1676 LONG ret;
1678 ret = InterlockedDecrement(&This->prop_ref);
1679 TRACE("new refcount %d\n", ret);
1681 return ret;
1684 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1685 REFGUID guidPropSet, ULONG dwPropID,
1686 LPVOID pInstanceData, ULONG cbInstanceData,
1687 LPVOID pPropData, ULONG cbPropData,
1688 PULONG pcbReturned)
1690 DS8Primary *This = impl_from_IKsPropertySet(iface);
1691 HRESULT res = E_PROP_ID_UNSUPPORTED;
1693 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1694 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1696 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1698 EnterCriticalSection(&This->crst);
1700 if(This->effect == 0)
1701 res = E_PROP_ID_UNSUPPORTED;
1702 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1704 res = DSERR_INVALIDPARAM;
1705 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1707 union {
1708 void *v;
1709 EAXLISTENERPROPERTIES *props;
1710 } data = { pPropData };
1712 *data.props = This->eax_prop;
1713 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1714 res = DS_OK;
1717 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1719 res = DSERR_INVALIDPARAM;
1720 if(cbPropData >= sizeof(LONG))
1722 union {
1723 void *v;
1724 LONG *l;
1725 } data = { pPropData };
1727 *data.l = This->eax_prop.lRoom;
1728 *pcbReturned = sizeof(LONG);
1729 res = DS_OK;
1732 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1734 res = DSERR_INVALIDPARAM;
1735 if(cbPropData >= sizeof(LONG))
1737 union {
1738 void *v;
1739 LONG *l;
1740 } data = { pPropData };
1742 *data.l = This->eax_prop.lRoomHF;
1743 *pcbReturned = sizeof(LONG);
1744 res = DS_OK;
1747 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1749 res = DSERR_INVALIDPARAM;
1750 if(cbPropData >= sizeof(FLOAT))
1752 union {
1753 void *v;
1754 FLOAT *fl;
1755 } data = { pPropData };
1757 *data.fl = This->eax_prop.flRoomRolloffFactor;
1758 *pcbReturned = sizeof(FLOAT);
1759 res = DS_OK;
1762 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1764 res = DSERR_INVALIDPARAM;
1765 if(cbPropData >= sizeof(DWORD))
1767 union {
1768 void *v;
1769 DWORD *dw;
1770 } data = { pPropData };
1772 *data.dw = This->eax_prop.dwEnvironment;
1773 *pcbReturned = sizeof(DWORD);
1774 res = DS_OK;
1777 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1779 res = DSERR_INVALIDPARAM;
1780 if(cbPropData >= sizeof(FLOAT))
1782 union {
1783 void *v;
1784 FLOAT *fl;
1785 } data = { pPropData };
1787 *data.fl = This->eax_prop.flEnvironmentSize;
1788 *pcbReturned = sizeof(FLOAT);
1789 res = DS_OK;
1792 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1794 res = DSERR_INVALIDPARAM;
1795 if(cbPropData >= sizeof(FLOAT))
1797 union {
1798 void *v;
1799 FLOAT *fl;
1800 } data = { pPropData };
1802 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1803 *pcbReturned = sizeof(FLOAT);
1804 res = DS_OK;
1807 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1809 res = DSERR_INVALIDPARAM;
1810 if(cbPropData >= sizeof(FLOAT))
1812 union {
1813 void *v;
1814 FLOAT *fl;
1815 } data = { pPropData };
1817 *data.fl = This->eax_prop.flAirAbsorptionHF;
1818 *pcbReturned = sizeof(FLOAT);
1819 res = DS_OK;
1822 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1824 res = DSERR_INVALIDPARAM;
1825 if(cbPropData >= sizeof(DWORD))
1827 union {
1828 void *v;
1829 DWORD *dw;
1830 } data = { pPropData };
1832 *data.dw = This->eax_prop.dwFlags;
1833 *pcbReturned = sizeof(DWORD);
1834 res = DS_OK;
1837 else
1838 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1840 LeaveCriticalSection(&This->crst);
1842 else
1843 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1845 return res;
1848 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1849 REFGUID guidPropSet, ULONG dwPropID,
1850 LPVOID pInstanceData, ULONG cbInstanceData,
1851 LPVOID pPropData, ULONG cbPropData)
1853 DS8Primary *This = impl_from_IKsPropertySet(iface);
1854 HRESULT res = E_PROP_ID_UNSUPPORTED;
1856 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1857 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1859 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1861 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1862 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1864 EnterCriticalSection(&This->crst);
1865 setALContext(This->ctx);
1867 if(This->effect == 0)
1868 res = E_PROP_ID_UNSUPPORTED;
1869 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1871 do_allparams:
1872 res = DSERR_INVALIDPARAM;
1873 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1875 union {
1876 const void *v;
1877 const EAXLISTENERPROPERTIES *props;
1878 } data = { pPropData };
1880 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1881 This->eax_prop = *data.props;
1882 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1883 (data.props->flEnvironmentSize < 2.0f) ?
1884 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1885 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1886 data.props->flEnvironmentDiffusion);
1888 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1889 mB_to_gain(data.props->lRoom));
1890 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1891 mB_to_gain(data.props->lRoomHF));
1893 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1894 data.props->flRoomRolloffFactor);
1896 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1897 data.props->flDecayTime);
1898 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1899 data.props->flDecayHFRatio);
1901 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1902 mB_to_gain(data.props->lReflections));
1903 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1904 data.props->flReflectionsDelay);
1906 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1907 mB_to_gain(data.props->lReverb));
1908 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1909 data.props->flReverbDelay);
1911 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1912 mB_to_gain(data.props->flAirAbsorptionHF));
1914 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1915 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1916 AL_TRUE : AL_FALSE);
1918 getALError();
1920 This->dirty.bit.effect = 1;
1921 res = DS_OK;
1924 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1926 res = DSERR_INVALIDPARAM;
1927 if(cbPropData >= sizeof(LONG))
1929 union {
1930 const void *v;
1931 const LONG *l;
1932 } data = { pPropData };
1934 This->eax_prop.lRoom = *data.l;
1935 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1936 mB_to_gain(This->eax_prop.lRoom));
1937 getALError();
1939 This->dirty.bit.effect = 1;
1940 res = DS_OK;
1943 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1945 res = DSERR_INVALIDPARAM;
1946 if(cbPropData >= sizeof(LONG))
1948 union {
1949 const void *v;
1950 const LONG *l;
1951 } data = { pPropData };
1953 This->eax_prop.lRoomHF = *data.l;
1954 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1955 mB_to_gain(This->eax_prop.lRoomHF));
1956 getALError();
1958 This->dirty.bit.effect = 1;
1959 res = DS_OK;
1962 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1964 res = DSERR_INVALIDPARAM;
1965 if(cbPropData >= sizeof(FLOAT))
1967 union {
1968 const void *v;
1969 const FLOAT *fl;
1970 } data = { pPropData };
1972 This->eax_prop.flRoomRolloffFactor = *data.fl;
1973 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1974 This->eax_prop.flRoomRolloffFactor);
1975 getALError();
1977 This->dirty.bit.effect = 1;
1978 res = DS_OK;
1981 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1983 res = DSERR_INVALIDPARAM;
1984 if(cbPropData >= sizeof(DWORD))
1986 union {
1987 const void *v;
1988 const DWORD *dw;
1989 } data = { pPropData };
1991 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1993 /* Get the environment index's default and pass it down to
1994 * ALLPARAMETERS */
1995 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1996 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1997 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1998 goto do_allparams;
2002 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
2004 res = DSERR_INVALIDPARAM;
2005 if(cbPropData >= sizeof(FLOAT))
2007 union {
2008 const void *v;
2009 const FLOAT *fl;
2010 } data = { pPropData };
2012 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2014 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2016 This->eax_prop.flEnvironmentSize = *data.fl;
2018 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2020 This->eax_prop.flDecayTime *= scale;
2021 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2023 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2025 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2026 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2028 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2030 This->eax_prop.flReflectionsDelay *= scale;
2031 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2033 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2035 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2036 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2038 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2040 This->eax_prop.flReverbDelay *= scale;
2041 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2044 /* Pass the updated environment properties down to ALLPARAMETERS */
2045 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2046 pPropData = (void*)&This->eax_prop;
2047 cbPropData = sizeof(This->eax_prop);
2048 goto do_allparams;
2052 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
2054 res = DSERR_INVALIDPARAM;
2055 if(cbPropData >= sizeof(FLOAT))
2057 union {
2058 const void *v;
2059 const FLOAT *fl;
2060 } data = { pPropData };
2062 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2063 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2064 This->eax_prop.flEnvironmentDiffusion);
2065 getALError();
2067 This->dirty.bit.effect = 1;
2068 res = DS_OK;
2071 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
2073 res = DSERR_INVALIDPARAM;
2074 if(cbPropData >= sizeof(FLOAT))
2076 union {
2077 const void *v;
2078 const FLOAT *fl;
2079 } data = { pPropData };
2081 This->eax_prop.flAirAbsorptionHF = *data.fl;
2082 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2083 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2084 getALError();
2086 This->dirty.bit.effect = 1;
2087 res = DS_OK;
2090 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
2092 res = DSERR_INVALIDPARAM;
2093 if(cbPropData >= sizeof(DWORD))
2095 union {
2096 const void *v;
2097 const DWORD *dw;
2098 } data = { pPropData };
2100 This->eax_prop.dwFlags = *data.dw;
2101 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2102 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2103 AL_TRUE : AL_FALSE);
2104 getALError();
2106 This->dirty.bit.effect = 1;
2107 res = DS_OK;
2110 else if(propid != 0)
2111 FIXME("Unhandled propid: 0x%08x\n", propid);
2113 if(res == DS_OK && immediate)
2114 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2116 popALContext();
2117 LeaveCriticalSection(&This->crst);
2119 else
2120 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2122 return res;
2125 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2126 REFGUID guidPropSet, ULONG dwPropID,
2127 PULONG pTypeSupport)
2129 DS8Primary *This = impl_from_IKsPropertySet(iface);
2130 HRESULT res = E_PROP_ID_UNSUPPORTED;
2132 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
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%08x\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