Use a separate thread to handle timer events
[wine/multimedia.git] / primary.c
blob0b21a6f012f925efb1300e519f30c993a63d0ff4
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_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 DWORD CALLBACK ThreadProc(void *dwUser)
105 DS8Primary *prim = (DS8Primary*)dwUser;
106 DWORD i;
107 MSG msg;
109 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
111 while(GetMessageA(&msg, NULL, 0, 0))
113 if(msg.message != WM_USER)
114 continue;
116 EnterCriticalSection(&prim->crst);
117 setALContext(prim->ctx);
119 /* OpenAL doesn't support our lovely buffer extensions
120 * so just make sure enough buffers are queued
122 if(!prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferSubData &&
123 !prim->ExtAL.BufferDataStatic)
125 for(i = 0;i < prim->nbuffers;++i)
127 DS8Buffer *buf = prim->buffers[i];
128 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
129 ALuint which, ofs;
131 if(buf->buffer->numsegs == 1 || !buf->isplaying)
132 continue;
134 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
135 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
136 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
138 queued -= done;
139 while(done--)
140 alSourceUnqueueBuffers(buf->source, 1, &which);
141 while(queued < QBUFFERS)
143 which = buf->buffer->buffers[buf->curidx];
144 ofs = buf->curidx*buf->buffer->segsize;
145 if(buf->curidx < buf->buffer->numsegs-1)
146 alBufferData(which, buf->buffer->buf_format,
147 buf->buffer->data + ofs, buf->buffer->segsize,
148 buf->buffer->format.Format.nSamplesPerSec);
149 else
150 alBufferData(which, buf->buffer->buf_format,
151 buf->buffer->data + ofs, buf->buffer->lastsegsize,
152 buf->buffer->format.Format.nSamplesPerSec);
154 alSourceQueueBuffers(buf->source, 1, &which);
155 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
156 queued++;
158 if(!buf->curidx && !buf->islooping)
160 buf->isplaying = FALSE;
161 break;
164 if(state != AL_PLAYING)
166 if(!queued)
168 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
169 continue;
171 alSourcePlay(buf->source);
173 getALError();
177 for(i = 0;i < prim->nnotifies;)
179 DS8Buffer *buf = prim->notifies[i];
180 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
181 DWORD status, curpos;
182 HRESULT hr;
184 hr = IDirectSoundBuffer8_GetStatus(dsb, &status);
185 if(SUCCEEDED(hr))
187 if(!(status&DSBSTATUS_PLAYING))
189 /* Stop will remove this buffer from list,
190 * and put another at the current position
191 * don't increment i
193 IDirectSoundBuffer8_Stop(dsb);
194 continue;
196 hr = IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
197 if(SUCCEEDED(hr) && buf->lastpos != curpos)
199 trigger_notifies(buf, buf->lastpos, curpos);
200 buf->lastpos = curpos;
203 i++;
205 popALContext();
206 LeaveCriticalSection(&prim->crst);
208 return 0;
212 HRESULT DS8Primary_Create(DS8Primary **ppv, DS8Impl *parent)
214 HRESULT hr = DSERR_OUTOFMEMORY;
215 DS8Primary *This = NULL;
216 DS3DLISTENER *listener;
217 WAVEFORMATEX *wfx;
218 ALuint srcs[256];
219 DWORD nsources;
221 *ppv = NULL;
222 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
223 if(!This) return hr;
225 This->IDirectSoundBuffer_iface.lpVtbl = (IDirectSoundBufferVtbl*)&DS8Primary_Vtbl;
226 This->IDirectSound3DListener_iface.lpVtbl = (IDirectSound3DListenerVtbl*)&DS8Primary3D_Vtbl;
227 This->IKsPropertySet_iface.lpVtbl = (IKsPropertySetVtbl*)&DS8PrimaryProp_Vtbl;
229 InitializeCriticalSection(&This->crst);
230 This->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DS8Primary.crst");
232 /* Allocate enough for a WAVEFORMATEXTENSIBLE */
233 wfx = &This->format.Format;
235 hr = DSERR_NODRIVER;
236 This->ctx = alcCreateContext(parent->device, NULL);
237 if(!This->ctx)
239 ALCenum err = alcGetError(parent->device);
240 ERR("Could not create context (0x%x)!\n", err);
241 goto fail;
244 setALContext(This->ctx);
245 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
247 TRACE("Found AL_EXT_FLOAT32\n");
248 This->SupportedExt[EXT_FLOAT32] = AL_TRUE;
250 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
252 TRACE("Found AL_EXT_MCFORMATS\n");
253 This->SupportedExt[EXT_MCFORMATS] = AL_TRUE;
255 if(alIsExtensionPresent("AL_EXT_STATIC_BUFFER"))
257 TRACE("Found AL_EXT_STATIC_BUFFER\n");
258 This->ExtAL.BufferDataStatic = alGetProcAddress("alBufferDataStatic");
259 This->SupportedExt[EXT_STATIC_BUFFER] = AL_TRUE;
261 if(alIsExtensionPresent("AL_SOFTX_buffer_samples"))
263 TRACE("Found AL_SOFTX_buffer_samples\n");
264 This->ExtAL.BufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
265 This->ExtAL.BufferSubSamplesSOFT = alGetProcAddress("alBufferSubSamplesSOFT");
266 This->ExtAL.GetBufferSamplesSOFT = alGetProcAddress("alGetBufferSamplesSOFT");
267 This->ExtAL.IsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
268 This->SupportedExt[SOFT_BUFFER_SAMPLES] = AL_TRUE;
270 if(alIsExtensionPresent("AL_SOFT_buffer_sub_data"))
272 TRACE("Found AL_SOFT_buffer_sub_data\n");
273 This->ExtAL.BufferSubData = alGetProcAddress("alBufferSubDataSOFT");
274 This->SupportedExt[SOFT_BUFFER_SUB_DATA] = AL_TRUE;
276 if(alIsExtensionPresent("AL_SOFTX_deferred_updates"))
278 TRACE("Found AL_SOFTX_deferred_updates\n");
279 This->ExtAL.DeferUpdates = alGetProcAddress("alDeferUpdatesSOFT");
280 This->ExtAL.ProcessUpdates = alGetProcAddress("alProcessUpdatesSOFT");
281 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
283 else
285 This->ExtAL.DeferUpdates = wrap_DeferUpdates;
286 This->ExtAL.ProcessUpdates = wrap_ProcessUpdates;
289 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
291 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
292 LOAD_FUNC(GenEffects);
293 LOAD_FUNC(DeleteEffects);
294 LOAD_FUNC(Effecti);
295 LOAD_FUNC(Effectf);
297 LOAD_FUNC(GenAuxiliaryEffectSlots);
298 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
299 LOAD_FUNC(AuxiliaryEffectSloti);
300 #undef LOAD_FUNC
301 This->SupportedExt[EXT_EFX] = AL_TRUE;
303 This->ExtAL.GenEffects(1, &This->effect);
304 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
306 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
308 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
310 wfx->wFormatTag = WAVE_FORMAT_PCM;
311 wfx->nChannels = 2;
312 wfx->wBitsPerSample = 8;
313 wfx->nSamplesPerSec = 22050;
314 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
315 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
316 wfx->cbSize = 0;
318 This->stopped = TRUE;
319 This->parent = parent;
320 /* Apparently primary buffer size is always 32k,
321 * tested on windows with 192k 24 bits sound @ 6 channels
322 * where it will run out in 60 ms and it isn't pointer aligned
324 This->buf_size = 32768;
326 if(!This->ExtAL.BufferSubData && !This->ExtAL.BufferSamplesSOFT &&
327 !This->ExtAL.BufferDataStatic)
329 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
330 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
331 ERR("Please consider using OpenAL-Soft\n");
334 /* Make sure DS3DListener defaults are applied to OpenAL */
335 listener = &This->listen;
336 listener->dwSize = sizeof(*listener);
337 listener->vPosition.x = 0.0;
338 listener->vPosition.y = 0.0;
339 listener->vPosition.z = 0.0;
340 listener->vVelocity.x = 0.0;
341 listener->vVelocity.y = 0.0;
342 listener->vVelocity.z = 0.0;
343 listener->vOrientFront.x = 0.0;
344 listener->vOrientFront.y = 0.0;
345 listener->vOrientFront.z = 1.0;
346 listener->vOrientTop.x = 0.0;
347 listener->vOrientTop.y = 1.0;
348 listener->vOrientTop.z = 0.0;
349 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
350 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
351 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
352 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
353 if(FAILED(hr))
354 ERR("Could not set 3d parameters: %08x\n", hr);
356 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
358 alGenSources(1, &srcs[nsources]);
359 if(alGetError() != AL_NO_ERROR)
360 break;
362 alDeleteSources(nsources, srcs);
363 getALError();
365 popALContext();
367 This->max_sources = nsources;
368 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
370 hr = DSERR_OUTOFMEMORY;
371 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
372 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
373 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
374 if(!This->sources || !This->buffers || !This->notifies)
375 goto fail;
377 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
378 if(This->thread_hdl == NULL)
379 goto fail;
381 *ppv = This;
382 return S_OK;
384 fail:
385 DS8Primary_Destroy(This);
386 return hr;
389 void DS8Primary_Destroy(DS8Primary *This)
391 TRACE("Destroying primary %p\n", This);
393 if(This->timer_id)
395 timeKillEvent(This->timer_id);
396 timeEndPeriod(This->timer_res);
397 TRACE("Killed timer\n");
399 if(This->thread_hdl)
401 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
402 WaitForSingleObject(This->thread_hdl, 1000);
403 CloseHandle(This->thread_hdl);
406 if(This->ctx)
408 /* Calling setALContext is not appropriate here,
409 * since we *have* to unset the context before destroying it
411 ALCcontext *old_ctx;
413 EnterCriticalSection(&openal_crst);
414 old_ctx = get_context();
415 if(old_ctx != This->ctx)
416 set_context(This->ctx);
417 else
418 old_ctx = NULL;
420 while(This->nbuffers--)
421 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
423 if(This->nsources)
424 alDeleteSources(This->nsources, This->sources);
426 if(This->effect)
427 This->ExtAL.DeleteEffects(1, &This->effect);
428 if(This->auxslot)
429 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
431 HeapFree(GetProcessHeap(), 0, This->sources);
432 HeapFree(GetProcessHeap(), 0, This->notifies);
433 HeapFree(GetProcessHeap(), 0, This->buffers);
435 set_context(old_ctx);
436 alcDestroyContext(This->ctx);
437 LeaveCriticalSection(&openal_crst);
440 This->crst.DebugInfo->Spare[0] = 0;
441 DeleteCriticalSection(&This->crst);
443 HeapFree(GetProcessHeap(), 0, This);
446 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
448 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
451 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
453 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
455 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
457 *ppv = NULL;
458 if(IsEqualIID(riid, &IID_IUnknown) ||
459 IsEqualIID(riid, &IID_IDirectSoundBuffer))
460 *ppv = &This->IDirectSoundBuffer_iface;
461 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
463 if((This->flags&DSBCAPS_CTRL3D))
464 *ppv = &This->IDirectSound3DListener_iface;
466 else
467 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
469 if(*ppv)
471 IUnknown_AddRef((IUnknown*)*ppv);
472 return S_OK;
475 return E_NOINTERFACE;
478 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
480 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
481 LONG ret;
483 ret = InterlockedIncrement(&This->ref);
484 if(This->ref == 1)
485 This->flags = 0;
487 return ret;
490 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
492 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
493 LONG ret;
495 ret = InterlockedDecrement(&This->ref);
497 return ret;
500 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
502 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
504 TRACE("(%p)->(%p)\n", iface, caps);
506 if(!caps || caps->dwSize < sizeof(*caps))
508 WARN("Invalid DSBCAPS (%p, %u)\n", caps, caps ? caps->dwSize : 0);
509 return DSERR_INVALIDPARAM;
512 EnterCriticalSection(&This->crst);
513 caps->dwFlags = This->flags;
514 caps->dwBufferBytes = This->buf_size;
515 caps->dwUnlockTransferRate = 0;
516 caps->dwPlayCpuOverhead = 0;
517 LeaveCriticalSection(&This->crst);
519 return DS_OK;
522 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
524 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
525 HRESULT hr = DSERR_PRIOLEVELNEEDED;
527 EnterCriticalSection(&This->crst);
528 if(This->write_emu)
529 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
530 LeaveCriticalSection(&This->crst);
532 return hr;
535 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
537 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
538 HRESULT hr = S_OK;
539 UINT size;
541 if(!wfx && !written)
543 WARN("Cannot report format or format size\n");
544 return DSERR_INVALIDPARAM;
547 EnterCriticalSection(&This->crst);
548 size = sizeof(This->format.Format) + This->format.Format.cbSize;
549 if(written)
550 *written = size;
551 if(wfx)
553 if(allocated < size)
554 hr = DSERR_INVALIDPARAM;
555 else
556 memcpy(wfx, &This->format.Format, size);
558 LeaveCriticalSection(&This->crst);
560 return hr;
563 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
565 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
566 HRESULT hr = S_OK;
568 TRACE("(%p)->(%p)\n", iface, volume);
570 if(!volume)
571 return DSERR_INVALIDPARAM;
573 EnterCriticalSection(&This->crst);
574 if(!(This->flags & DSBCAPS_CTRLVOLUME))
575 hr = DSERR_CONTROLUNAVAIL;
576 else
578 ALfloat gain;
579 LONG vol;
581 setALContext(This->ctx);
582 alGetListenerf(AL_GAIN, &gain);
583 getALError();
584 popALContext();
586 vol = gain_to_mB(gain);
587 vol = max(vol, DSBVOLUME_MIN);
588 *volume = min(vol, DSBVOLUME_MAX);
590 LeaveCriticalSection(&This->crst);
592 return hr;
595 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
597 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
598 HRESULT hr = S_OK;
600 WARN("(%p)->(%p): semi-stub\n", iface, pan);
602 if(!pan)
603 return DSERR_INVALIDPARAM;
605 EnterCriticalSection(&This->crst);
606 if(This->write_emu)
607 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
608 else if(!(This->flags & DSBCAPS_CTRLPAN))
609 hr = DSERR_CONTROLUNAVAIL;
610 else
611 *pan = 0;
612 LeaveCriticalSection(&This->crst);
614 return hr;
617 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
619 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
620 HRESULT hr = S_OK;
622 WARN("(%p)->(%p): semi-stub\n", iface, freq);
624 if(!freq)
625 return DSERR_INVALIDPARAM;
627 EnterCriticalSection(&This->crst);
628 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
629 hr = DSERR_CONTROLUNAVAIL;
630 else
631 *freq = This->format.Format.nSamplesPerSec;
632 LeaveCriticalSection(&This->crst);
634 return hr;
637 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
639 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
641 TRACE("(%p)->(%p)\n", iface, status);
643 if(!status)
644 return DSERR_INVALIDPARAM;
646 EnterCriticalSection(&This->crst);
648 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
649 if((This->flags&DSBCAPS_LOCDEFER))
650 *status |= DSBSTATUS_LOCHARDWARE;
652 if(This->stopped)
654 DWORD i, state;
655 HRESULT hr;
657 for(i = 0;i < This->nbuffers;++i)
659 hr = IDirectSoundBuffer_GetStatus((IDirectSoundBuffer*)This->buffers[i], &state);
660 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
661 break;
663 if(i == This->nbuffers)
665 /* Primary stopped and no buffers playing.. */
666 *status = 0;
670 LeaveCriticalSection(&This->crst);
672 return S_OK;
675 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
677 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
678 HRESULT hr = S_OK;
680 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
682 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
684 WARN("Bad DSBDESC for primary buffer\n");
685 return DSERR_INVALIDPARAM;
687 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
688 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
689 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
691 WARN("Bad dwFlags %08x\n", desc->dwFlags);
692 return DSERR_INVALIDPARAM;
695 EnterCriticalSection(&This->crst);
696 /* Should be 0 if not initialized */
697 if(This->flags)
699 hr = DSERR_ALREADYINITIALIZED;
700 goto out;
703 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
705 DSBUFFERDESC emudesc;
706 DS8Buffer *emu;
708 if(This->write_emu)
710 ERR("There shouldn't be a write_emu!\n");
711 IDirectSoundBuffer8_Release(This->write_emu);
712 This->write_emu = NULL;
715 memset(&emudesc, 0, sizeof(emudesc));
716 emudesc.dwSize = sizeof(emudesc);
717 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
718 /* Dont play last incomplete sample */
719 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
720 emudesc.lpwfxFormat = &This->format.Format;
722 hr = DS8Buffer_Create(&emu, This, NULL);
723 if(SUCCEEDED(hr))
725 This->write_emu = &emu->IDirectSoundBuffer8_iface;
726 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
727 if(FAILED(hr))
729 IDirectSoundBuffer8_Release(This->write_emu);
730 This->write_emu = NULL;
735 if(SUCCEEDED(hr))
736 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
737 out:
738 LeaveCriticalSection(&This->crst);
739 return hr;
742 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
744 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
745 HRESULT hr = DSERR_PRIOLEVELNEEDED;
747 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
749 EnterCriticalSection(&This->crst);
750 if(This->write_emu)
751 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
752 LeaveCriticalSection(&This->crst);
754 return hr;
757 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
759 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
760 HRESULT hr;
762 TRACE("(%p)->(%u, %u, %u)\n", iface, res1, res2, flags);
764 if(!(flags & DSBPLAY_LOOPING))
766 WARN("Flags (%08x) not set to DSBPLAY_LOOPING\n", flags);
767 return DSERR_INVALIDPARAM;
770 EnterCriticalSection(&This->crst);
771 hr = S_OK;
772 if(This->write_emu)
773 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
774 if(SUCCEEDED(hr))
775 This->stopped = FALSE;
776 LeaveCriticalSection(&This->crst);
778 return hr;
781 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
783 WARN("(%p)->(%u)\n", iface, pos);
784 return DSERR_INVALIDCALL;
787 /* Just assume the format is crap, and clean up the damage */
788 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
790 if(from->wFormatTag == WAVE_FORMAT_PCM)
792 wfx->cbSize = 0;
793 if(from->wBitsPerSample == 8 ||
794 from->wBitsPerSample == 16 ||
795 from->wBitsPerSample == 24 ||
796 from->wBitsPerSample == 32)
797 wfx->wBitsPerSample = from->wBitsPerSample;
799 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
801 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
802 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
803 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
805 /* Fail silently.. */
806 if(from->cbSize < size)
807 return;
808 if(!fromx->Samples.wValidBitsPerSample &&
809 !fromx->Format.wBitsPerSample)
810 return;
812 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
813 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
815 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
816 return;
819 wfe->Format.wBitsPerSample = from->wBitsPerSample;
820 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
821 if(!wfe->Samples.wValidBitsPerSample)
822 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
823 wfe->Format.cbSize = size;
824 wfe->dwChannelMask = fromx->dwChannelMask;
825 wfe->SubFormat = fromx->SubFormat;
827 else
829 ERR("Unhandled format tag %04x\n", from->wFormatTag);
830 return;
833 if(from->nChannels)
834 wfx->nChannels = from->nChannels;
835 wfx->wFormatTag = from->wFormatTag;
836 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
837 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
838 wfx->nSamplesPerSec = from->nSamplesPerSec;
839 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
840 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
843 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
845 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
846 HRESULT hr = S_OK;
847 ALCint freq;
849 TRACE("(%p)->(%p)\n", iface, wfx);
851 if(!wfx)
853 WARN("Missing format\n");
854 return DSERR_INVALIDPARAM;
857 EnterCriticalSection(&This->crst);
859 if(This->parent->prio_level < DSSCL_PRIORITY)
861 hr = DSERR_PRIOLEVELNEEDED;
862 goto out;
865 TRACE("Requested primary format:\n"
866 " FormatTag = %04x\n"
867 " Channels = %u\n"
868 " SamplesPerSec = %u\n"
869 " AvgBytesPerSec = %u\n"
870 " BlockAlign = %u\n"
871 " BitsPerSample = %u\n",
872 wfx->wFormatTag, wfx->nChannels,
873 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
874 wfx->nBlockAlign, wfx->wBitsPerSample);
876 copy_waveformat(&This->format.Format, wfx);
878 freq = This->format.Format.nSamplesPerSec;
879 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
880 getALCError(This->parent->device);
882 This->format.Format.nSamplesPerSec = freq;
883 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
884 This->format.Format.nSamplesPerSec;
886 if(This->write_emu)
888 DS8Buffer *buf;
889 DSBUFFERDESC desc;
891 memset(&desc, 0, sizeof(desc));
892 desc.dwSize = sizeof(desc);
893 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
894 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
895 desc.lpwfxFormat = &This->format.Format;
897 hr = DS8Buffer_Create(&buf, This, NULL);
898 if(FAILED(hr))
899 goto out;
901 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, (IDirectSound*)&This->parent->IDirectSound8_iface, &desc);
902 if(FAILED(hr))
903 DS8Buffer_Destroy(buf);
904 else
906 IDirectSoundBuffer8_Release(This->write_emu);
907 This->write_emu = &buf->IDirectSoundBuffer8_iface;
911 out:
912 LeaveCriticalSection(&This->crst);
913 return hr;
916 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
918 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
919 HRESULT hr = S_OK;
921 TRACE("(%p)->(%d)\n", iface, vol);
923 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
925 WARN("Invalid volume (%d)\n", vol);
926 return DSERR_INVALIDPARAM;
929 EnterCriticalSection(&This->crst);
930 if(!(This->flags&DSBCAPS_CTRLVOLUME))
931 hr = DSERR_CONTROLUNAVAIL;
932 if(SUCCEEDED(hr))
934 setALContext(This->ctx);
935 alListenerf(AL_GAIN, mB_to_gain(vol));
936 popALContext();
938 LeaveCriticalSection(&This->crst);
940 return hr;
943 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
945 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
946 HRESULT hr;
948 TRACE("(%p)->(%d)\n", iface, pan);
950 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
952 WARN("invalid parameter: pan = %d\n", pan);
953 return DSERR_INVALIDPARAM;
956 EnterCriticalSection(&This->crst);
957 if(!(This->flags&DSBCAPS_CTRLPAN))
959 WARN("control unavailable\n");
960 hr = DSERR_CONTROLUNAVAIL;
962 else if(This->write_emu)
963 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
964 else
966 FIXME("Not supported\n");
967 hr = E_NOTIMPL;
969 LeaveCriticalSection(&This->crst);
971 return hr;
974 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
976 WARN("(%p)->(%u)\n", iface, freq);
977 return DSERR_CONTROLUNAVAIL;
980 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
982 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
983 HRESULT hr = S_OK;
985 TRACE("(%p)->()\n", iface);
987 EnterCriticalSection(&This->crst);
988 if(This->write_emu)
989 hr = IDirectSoundBuffer8_Stop(This->write_emu);
990 if(SUCCEEDED(hr))
991 This->stopped = TRUE;
992 LeaveCriticalSection(&This->crst);
994 return hr;
997 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
999 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1000 HRESULT hr = DSERR_INVALIDCALL;
1002 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1004 EnterCriticalSection(&This->crst);
1005 if(This->write_emu)
1006 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1007 LeaveCriticalSection(&This->crst);
1009 return hr;
1012 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1014 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1015 HRESULT hr = S_OK;
1017 TRACE("(%p)->()\n", iface);
1019 EnterCriticalSection(&This->crst);
1020 if(This->write_emu)
1021 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1022 LeaveCriticalSection(&This->crst);
1024 return hr;
1027 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1029 DS8Primary_QueryInterface,
1030 DS8Primary_AddRef,
1031 DS8Primary_Release,
1032 DS8Primary_GetCaps,
1033 DS8Primary_GetCurrentPosition,
1034 DS8Primary_GetFormat,
1035 DS8Primary_GetVolume,
1036 DS8Primary_GetPan,
1037 DS8Primary_GetFrequency,
1038 DS8Primary_GetStatus,
1039 DS8Primary_Initialize,
1040 DS8Primary_Lock,
1041 DS8Primary_Play,
1042 DS8Primary_SetCurrentPosition,
1043 DS8Primary_SetFormat,
1044 DS8Primary_SetVolume,
1045 DS8Primary_SetPan,
1046 DS8Primary_SetFrequency,
1047 DS8Primary_Stop,
1048 DS8Primary_Unlock,
1049 DS8Primary_Restore
1052 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
1054 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
1057 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1059 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1060 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1063 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1065 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1066 LONG ret;
1068 ret = InterlockedIncrement(&This->ds3d_ref);
1069 TRACE("new refcount %d\n", ret);
1071 return ret;
1075 /* Considering the primary buffer doesn't get destroyed
1076 * it doesn't make sense to destroy ds3d here
1078 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1080 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1081 LONG ret;
1083 ret = InterlockedDecrement(&This->ds3d_ref);
1084 TRACE("new refcount %d\n", ret);
1086 return ret;
1090 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1092 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1093 // HRESULT hr;
1095 TRACE("(%p)->(%p)\n", iface, listener);
1097 if(!listener || listener->dwSize < sizeof(*listener))
1099 WARN("Invalid DS3DLISTENER %p %u\n", listener, listener ? listener->dwSize : 0);
1100 return DSERR_INVALIDPARAM;
1103 EnterCriticalSection(&This->crst);
1104 setALContext(This->ctx);
1105 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1106 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1107 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1108 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1109 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1110 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1111 popALContext();
1112 LeaveCriticalSection(&This->crst);
1114 // return hr;
1115 return DS_OK;
1118 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1120 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1122 TRACE("(%p)->(%p)\n", iface, distancefactor);
1124 if(!distancefactor)
1126 WARN("Invalid parameter %p\n", distancefactor);
1127 return DSERR_INVALIDPARAM;
1130 EnterCriticalSection(&This->crst);
1131 setALContext(This->ctx);
1133 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1134 getALError();
1136 popALContext();
1137 LeaveCriticalSection(&This->crst);
1139 return S_OK;
1142 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1144 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1146 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1148 if(!dopplerfactor)
1150 WARN("Invalid parameter %p\n", dopplerfactor);
1151 return DSERR_INVALIDPARAM;
1154 EnterCriticalSection(&This->crst);
1155 setALContext(This->ctx);
1157 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1158 getALError();
1160 popALContext();
1161 LeaveCriticalSection(&This->crst);
1163 return S_OK;
1166 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1168 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1169 ALfloat orient[6];
1171 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1173 if(!front || !top)
1175 WARN("Invalid parameter %p %p\n", front, top);
1176 return DSERR_INVALIDPARAM;
1179 EnterCriticalSection(&This->crst);
1180 setALContext(This->ctx);
1182 alGetListenerfv(AL_ORIENTATION, orient);
1183 getALError();
1185 front->x = orient[0];
1186 front->y = orient[1];
1187 front->z = -orient[2];
1188 top->x = orient[3];
1189 top->y = orient[4];
1190 top->z = -orient[5];
1192 popALContext();
1193 LeaveCriticalSection(&This->crst);
1195 return S_OK;
1198 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1200 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1201 ALfloat alpos[3];
1203 TRACE("(%p)->(%p)\n", iface, pos);
1205 if(!pos)
1207 WARN("Invalid parameter %p\n", pos);
1208 return DSERR_INVALIDPARAM;
1211 EnterCriticalSection(&This->crst);
1212 setALContext(This->ctx);
1214 alGetListenerfv(AL_POSITION, alpos);
1215 getALError();
1217 pos->x = alpos[0];
1218 pos->y = alpos[1];
1219 pos->z = -alpos[2];
1221 popALContext();
1222 LeaveCriticalSection(&This->crst);
1224 return S_OK;
1227 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1229 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1231 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1233 if(!rollofffactor)
1235 WARN("Invalid parameter %p\n", rollofffactor);
1236 return DSERR_INVALIDPARAM;
1239 EnterCriticalSection(&This->crst);
1240 *rollofffactor = This->rollofffactor;
1241 LeaveCriticalSection(&This->crst);
1243 return S_OK;
1246 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1248 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1249 ALfloat vel[3];
1251 TRACE("(%p)->(%p)\n", iface, velocity);
1253 if(!velocity)
1255 WARN("Invalid parameter %p\n", velocity);
1256 return DSERR_INVALIDPARAM;
1259 EnterCriticalSection(&This->crst);
1260 setALContext(This->ctx);
1262 alGetListenerfv(AL_VELOCITY, vel);
1263 getALError();
1265 velocity->x = vel[0];
1266 velocity->y = vel[1];
1267 velocity->z = -vel[2];
1269 popALContext();
1270 LeaveCriticalSection(&This->crst);
1272 return S_OK;
1275 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1277 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1279 TRACE("(%p)->(%p, %u)\n", iface, listen, apply);
1281 if(!listen || listen->dwSize < sizeof(*listen))
1283 WARN("Invalid parameter %p %u\n", listen, listen ? listen->dwSize : 0);
1284 return DSERR_INVALIDPARAM;
1287 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1288 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1290 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1291 return DSERR_INVALIDPARAM;
1294 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1295 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1297 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1298 return DSERR_INVALIDPARAM;
1301 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1302 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1304 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1305 return DSERR_INVALIDPARAM;
1308 EnterCriticalSection(&This->crst);
1309 setALContext(This->ctx);
1310 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1311 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1312 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1313 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1314 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1315 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1316 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1317 popALContext();
1318 LeaveCriticalSection(&This->crst);
1320 return S_OK;
1323 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1325 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1327 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1329 if(factor < DS3D_MINDISTANCEFACTOR ||
1330 factor > DS3D_MAXDISTANCEFACTOR)
1332 WARN("Invalid parameter %f\n", factor);
1333 return DSERR_INVALIDPARAM;
1336 EnterCriticalSection(&This->crst);
1337 if(apply == DS3D_DEFERRED)
1339 This->listen.flDistanceFactor = factor;
1340 This->dirty.bit.distancefactor = 1;
1342 else
1344 setALContext(This->ctx);
1345 alSpeedOfSound(343.3f/factor);
1346 if(This->SupportedExt[EXT_EFX])
1347 alListenerf(AL_METERS_PER_UNIT, factor);
1348 getALError();
1349 popALContext();
1351 LeaveCriticalSection(&This->crst);
1353 return S_OK;
1356 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1358 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1360 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1362 if(factor < DS3D_MINDOPPLERFACTOR ||
1363 factor > DS3D_MAXDOPPLERFACTOR)
1365 WARN("Invalid parameter %f\n", factor);
1366 return DSERR_INVALIDPARAM;
1369 EnterCriticalSection(&This->crst);
1370 if(apply == DS3D_DEFERRED)
1372 This->listen.flDopplerFactor = factor;
1373 This->dirty.bit.dopplerfactor = 1;
1375 else
1377 setALContext(This->ctx);
1378 alDopplerFactor(factor);
1379 getALError();
1380 popALContext();
1382 LeaveCriticalSection(&This->crst);
1384 return S_OK;
1387 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1389 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1391 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1393 EnterCriticalSection(&This->crst);
1394 if(apply == DS3D_DEFERRED)
1396 This->listen.vOrientFront.x = xFront;
1397 This->listen.vOrientFront.y = yFront;
1398 This->listen.vOrientFront.z = zFront;
1399 This->listen.vOrientTop.x = xTop;
1400 This->listen.vOrientTop.y = yTop;
1401 This->listen.vOrientTop.z = zTop;
1402 This->dirty.bit.orientation = 1;
1404 else
1406 ALfloat orient[6] = {
1407 xFront, yFront, -zFront,
1408 xTop, yTop, -zTop
1410 setALContext(This->ctx);
1411 alListenerfv(AL_ORIENTATION, orient);
1412 getALError();
1413 popALContext();
1415 LeaveCriticalSection(&This->crst);
1417 return S_OK;
1420 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1422 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1424 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1426 EnterCriticalSection(&This->crst);
1427 if(apply == DS3D_DEFERRED)
1429 This->listen.vPosition.x = x;
1430 This->listen.vPosition.y = y;
1431 This->listen.vPosition.z = z;
1432 This->dirty.bit.pos = 1;
1434 else
1436 setALContext(This->ctx);
1437 alListener3f(AL_POSITION, x, y, -z);
1438 getALError();
1439 popALContext();
1441 LeaveCriticalSection(&This->crst);
1443 return S_OK;
1446 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1448 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1450 TRACE("(%p)->(%f, %u)\n", iface, factor, apply);
1452 if(factor < DS3D_MINROLLOFFFACTOR ||
1453 factor > DS3D_MAXROLLOFFFACTOR)
1455 WARN("Invalid parameter %f\n", factor);
1456 return DSERR_INVALIDPARAM;
1459 EnterCriticalSection(&This->crst);
1460 if(apply == DS3D_DEFERRED)
1462 This->listen.flRolloffFactor = factor;
1463 This->dirty.bit.rollofffactor = 1;
1465 else
1467 DWORD i;
1469 setALContext(This->ctx);
1470 for(i = 0;i < This->nbuffers;++i)
1472 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1473 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1475 getALError();
1476 popALContext();
1478 This->rollofffactor = factor;
1480 LeaveCriticalSection(&This->crst);
1482 return S_OK;
1485 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1487 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1489 TRACE("(%p)->(%f, %f, %f, %u)\n", iface, x, y, z, apply);
1491 EnterCriticalSection(&This->crst);
1492 if(apply == DS3D_DEFERRED)
1494 This->listen.vVelocity.x = x;
1495 This->listen.vVelocity.y = y;
1496 This->listen.vVelocity.z = z;
1497 This->dirty.bit.vel = 1;
1499 else
1501 setALContext(This->ctx);
1502 alListener3f(AL_VELOCITY, x, y, -z);
1503 getALError();
1504 popALContext();
1506 LeaveCriticalSection(&This->crst);
1508 return S_OK;
1511 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1513 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1514 const DS3DLISTENER *listen = &This->listen;
1515 DWORD i;
1517 EnterCriticalSection(&This->crst);
1518 setALContext(This->ctx);
1519 This->ExtAL.DeferUpdates();
1521 if(This->dirty.bit.pos)
1522 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1523 if(This->dirty.bit.vel)
1524 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1525 if(This->dirty.bit.orientation)
1527 ALfloat orient[6] = {
1528 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1529 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1531 alListenerfv(AL_ORIENTATION, orient);
1533 if(This->dirty.bit.distancefactor)
1535 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1536 if(This->SupportedExt[EXT_EFX])
1537 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1540 if(This->dirty.bit.rollofffactor)
1542 ALfloat rolloff = This->rollofffactor;
1543 for(i = 0;i < This->nbuffers;++i)
1545 DS8Buffer *buf = This->buffers[i];
1546 if(buf->ds3dmode != DS3DMODE_DISABLE)
1547 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1551 if(This->dirty.bit.dopplerfactor)
1552 alDopplerFactor(listen->flDopplerFactor);
1554 if(This->dirty.bit.effect)
1555 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1557 /* getALError is here for debugging */
1558 getALError();
1560 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1561 This->dirty.flags = 0;
1563 for(i = 0;i < This->nbuffers;++i)
1565 DS8Buffer *buf = This->buffers[i];
1567 if(!buf->dirty.flags)
1568 continue;
1570 if(buf->dirty.bit.pos)
1571 alSource3f(buf->source, AL_POSITION,
1572 buf->ds3dbuffer.vPosition.x,
1573 buf->ds3dbuffer.vPosition.y,
1574 -buf->ds3dbuffer.vPosition.z);
1575 if(buf->dirty.bit.vel)
1576 alSource3f(buf->source, AL_VELOCITY,
1577 buf->ds3dbuffer.vVelocity.x,
1578 buf->ds3dbuffer.vVelocity.y,
1579 -buf->ds3dbuffer.vVelocity.z);
1580 if(buf->dirty.bit.cone_angles)
1582 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1583 buf->ds3dbuffer.dwInsideConeAngle);
1584 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1585 buf->ds3dbuffer.dwOutsideConeAngle);
1587 if(buf->dirty.bit.cone_orient)
1588 alSource3f(buf->source, AL_DIRECTION,
1589 buf->ds3dbuffer.vConeOrientation.x,
1590 buf->ds3dbuffer.vConeOrientation.y,
1591 -buf->ds3dbuffer.vConeOrientation.z);
1592 if(buf->dirty.bit.cone_outsidevolume)
1593 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1594 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1595 if(buf->dirty.bit.min_distance)
1596 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1597 if(buf->dirty.bit.max_distance)
1598 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1599 if(buf->dirty.bit.mode)
1601 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1602 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1603 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1604 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1605 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1607 buf->dirty.flags = 0;
1609 getALError();
1611 This->ExtAL.ProcessUpdates();
1612 popALContext();
1613 LeaveCriticalSection(&This->crst);
1615 return S_OK;
1618 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1620 DS8Primary3D_QueryInterface,
1621 DS8Primary3D_AddRef,
1622 DS8Primary3D_Release,
1623 DS8Primary3D_GetAllParameters,
1624 DS8Primary3D_GetDistanceFactor,
1625 DS8Primary3D_GetDopplerFactor,
1626 DS8Primary3D_GetOrientation,
1627 DS8Primary3D_GetPosition,
1628 DS8Primary3D_GetRolloffFactor,
1629 DS8Primary3D_GetVelocity,
1630 DS8Primary3D_SetAllParameters,
1631 DS8Primary3D_SetDistanceFactor,
1632 DS8Primary3D_SetDopplerFactor,
1633 DS8Primary3D_SetOrientation,
1634 DS8Primary3D_SetPosition,
1635 DS8Primary3D_SetRolloffFactor,
1636 DS8Primary3D_SetVelocity,
1637 DS8Primary3D_CommitDeferredSettings
1640 /* NOTE: Although the app handles listener properties through secondary buffers,
1641 * we pass the requests to the primary buffer though a propertyset interface.
1642 * These methods are not exposed to the app. */
1643 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1645 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1648 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1650 DS8Primary *This = impl_from_IKsPropertySet(iface);
1651 return IDirectSoundBuffer_QueryInterface((IDirectSoundBuffer*)This, riid, ppv);
1654 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1656 DS8Primary *This = impl_from_IKsPropertySet(iface);
1657 LONG ret;
1659 ret = InterlockedIncrement(&This->prop_ref);
1660 TRACE("new refcount %d\n", ret);
1662 return ret;
1665 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1667 DS8Primary *This = impl_from_IKsPropertySet(iface);
1668 LONG ret;
1670 ret = InterlockedDecrement(&This->prop_ref);
1671 TRACE("new refcount %d\n", ret);
1673 return ret;
1676 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1677 REFGUID guidPropSet, ULONG dwPropID,
1678 LPVOID pInstanceData, ULONG cbInstanceData,
1679 LPVOID pPropData, ULONG cbPropData,
1680 PULONG pcbReturned)
1682 DS8Primary *This = impl_from_IKsPropertySet(iface);
1683 HRESULT res = E_PROP_ID_UNSUPPORTED;
1685 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
1686 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
1688 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1690 EnterCriticalSection(&This->crst);
1692 if(This->effect == 0)
1693 res = E_PROP_ID_UNSUPPORTED;
1694 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1696 res = DSERR_INVALIDPARAM;
1697 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1699 union {
1700 void *v;
1701 EAXLISTENERPROPERTIES *props;
1702 } data = { pPropData };
1704 *data.props = This->eax_prop;
1705 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1706 res = DS_OK;
1709 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOM)
1711 res = DSERR_INVALIDPARAM;
1712 if(cbPropData >= sizeof(LONG))
1714 union {
1715 void *v;
1716 LONG *l;
1717 } data = { pPropData };
1719 *data.l = This->eax_prop.lRoom;
1720 *pcbReturned = sizeof(LONG);
1721 res = DS_OK;
1724 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF)
1726 res = DSERR_INVALIDPARAM;
1727 if(cbPropData >= sizeof(LONG))
1729 union {
1730 void *v;
1731 LONG *l;
1732 } data = { pPropData };
1734 *data.l = This->eax_prop.lRoomHF;
1735 *pcbReturned = sizeof(LONG);
1736 res = DS_OK;
1739 else if(dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1741 res = DSERR_INVALIDPARAM;
1742 if(cbPropData >= sizeof(FLOAT))
1744 union {
1745 void *v;
1746 FLOAT *fl;
1747 } data = { pPropData };
1749 *data.fl = This->eax_prop.flRoomRolloffFactor;
1750 *pcbReturned = sizeof(FLOAT);
1751 res = DS_OK;
1754 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1756 res = DSERR_INVALIDPARAM;
1757 if(cbPropData >= sizeof(DWORD))
1759 union {
1760 void *v;
1761 DWORD *dw;
1762 } data = { pPropData };
1764 *data.dw = This->eax_prop.dwEnvironment;
1765 *pcbReturned = sizeof(DWORD);
1766 res = DS_OK;
1769 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1771 res = DSERR_INVALIDPARAM;
1772 if(cbPropData >= sizeof(FLOAT))
1774 union {
1775 void *v;
1776 FLOAT *fl;
1777 } data = { pPropData };
1779 *data.fl = This->eax_prop.flEnvironmentSize;
1780 *pcbReturned = sizeof(FLOAT);
1781 res = DS_OK;
1784 else if(dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
1786 res = DSERR_INVALIDPARAM;
1787 if(cbPropData >= sizeof(FLOAT))
1789 union {
1790 void *v;
1791 FLOAT *fl;
1792 } data = { pPropData };
1794 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1795 *pcbReturned = sizeof(FLOAT);
1796 res = DS_OK;
1799 else if(dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
1801 res = DSERR_INVALIDPARAM;
1802 if(cbPropData >= sizeof(FLOAT))
1804 union {
1805 void *v;
1806 FLOAT *fl;
1807 } data = { pPropData };
1809 *data.fl = This->eax_prop.flAirAbsorptionHF;
1810 *pcbReturned = sizeof(FLOAT);
1811 res = DS_OK;
1814 else if(dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
1816 res = DSERR_INVALIDPARAM;
1817 if(cbPropData >= sizeof(DWORD))
1819 union {
1820 void *v;
1821 DWORD *dw;
1822 } data = { pPropData };
1824 *data.dw = This->eax_prop.dwFlags;
1825 *pcbReturned = sizeof(DWORD);
1826 res = DS_OK;
1829 else
1830 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
1832 LeaveCriticalSection(&This->crst);
1834 else
1835 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1837 return res;
1840 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1841 REFGUID guidPropSet, ULONG dwPropID,
1842 LPVOID pInstanceData, ULONG cbInstanceData,
1843 LPVOID pPropData, ULONG cbPropData)
1845 DS8Primary *This = impl_from_IKsPropertySet(iface);
1846 HRESULT res = E_PROP_ID_UNSUPPORTED;
1848 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
1849 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
1851 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1853 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1854 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1856 EnterCriticalSection(&This->crst);
1857 setALContext(This->ctx);
1859 if(This->effect == 0)
1860 res = E_PROP_ID_UNSUPPORTED;
1861 else if(propid == DSPROPERTY_EAXLISTENER_ALLPARAMETERS)
1863 do_allparams:
1864 res = DSERR_INVALIDPARAM;
1865 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1867 union {
1868 const void *v;
1869 const EAXLISTENERPROPERTIES *props;
1870 } data = { pPropData };
1872 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1873 This->eax_prop = *data.props;
1874 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1875 (data.props->flEnvironmentSize < 2.0f) ?
1876 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1877 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1878 data.props->flEnvironmentDiffusion);
1880 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1881 mB_to_gain(data.props->lRoom));
1882 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1883 mB_to_gain(data.props->lRoomHF));
1885 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1886 data.props->flRoomRolloffFactor);
1888 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1889 data.props->flDecayTime);
1890 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1891 data.props->flDecayHFRatio);
1893 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1894 mB_to_gain(data.props->lReflections));
1895 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1896 data.props->flReflectionsDelay);
1898 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1899 mB_to_gain(data.props->lReverb));
1900 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1901 data.props->flReverbDelay);
1903 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1904 mB_to_gain(data.props->flAirAbsorptionHF));
1906 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1907 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1908 AL_TRUE : AL_FALSE);
1910 getALError();
1912 This->dirty.bit.effect = 1;
1913 res = DS_OK;
1916 else if(propid == DSPROPERTY_EAXLISTENER_ROOM)
1918 res = DSERR_INVALIDPARAM;
1919 if(cbPropData >= sizeof(LONG))
1921 union {
1922 const void *v;
1923 const LONG *l;
1924 } data = { pPropData };
1926 This->eax_prop.lRoom = *data.l;
1927 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1928 mB_to_gain(This->eax_prop.lRoom));
1929 getALError();
1931 This->dirty.bit.effect = 1;
1932 res = DS_OK;
1935 else if(propid == DSPROPERTY_EAXLISTENER_ROOMHF)
1937 res = DSERR_INVALIDPARAM;
1938 if(cbPropData >= sizeof(LONG))
1940 union {
1941 const void *v;
1942 const LONG *l;
1943 } data = { pPropData };
1945 This->eax_prop.lRoomHF = *data.l;
1946 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1947 mB_to_gain(This->eax_prop.lRoomHF));
1948 getALError();
1950 This->dirty.bit.effect = 1;
1951 res = DS_OK;
1954 else if(propid == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR)
1956 res = DSERR_INVALIDPARAM;
1957 if(cbPropData >= sizeof(FLOAT))
1959 union {
1960 const void *v;
1961 const FLOAT *fl;
1962 } data = { pPropData };
1964 This->eax_prop.flRoomRolloffFactor = *data.fl;
1965 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1966 This->eax_prop.flRoomRolloffFactor);
1967 getALError();
1969 This->dirty.bit.effect = 1;
1970 res = DS_OK;
1973 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENT)
1975 res = DSERR_INVALIDPARAM;
1976 if(cbPropData >= sizeof(DWORD))
1978 union {
1979 const void *v;
1980 const DWORD *dw;
1981 } data = { pPropData };
1983 if(*data.dw < EAX_ENVIRONMENT_COUNT)
1985 /* Get the environment index's default and pass it down to
1986 * ALLPARAMETERS */
1987 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
1988 pPropData = (void*)&EnvironmentDefaults[*data.dw];
1989 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
1990 goto do_allparams;
1994 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE)
1996 res = DSERR_INVALIDPARAM;
1997 if(cbPropData >= sizeof(FLOAT))
1999 union {
2000 const void *v;
2001 const FLOAT *fl;
2002 } data = { pPropData };
2004 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2006 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2008 This->eax_prop.flEnvironmentSize = *data.fl;
2010 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2012 This->eax_prop.flDecayTime *= scale;
2013 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2015 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2017 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2018 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2020 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2022 This->eax_prop.flReflectionsDelay *= scale;
2023 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2025 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2027 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2028 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2030 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2032 This->eax_prop.flReverbDelay *= scale;
2033 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2036 /* Pass the updated environment properties down to ALLPARAMETERS */
2037 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2038 pPropData = (void*)&This->eax_prop;
2039 cbPropData = sizeof(This->eax_prop);
2040 goto do_allparams;
2044 else if(propid == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION)
2046 res = DSERR_INVALIDPARAM;
2047 if(cbPropData >= sizeof(FLOAT))
2049 union {
2050 const void *v;
2051 const FLOAT *fl;
2052 } data = { pPropData };
2054 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2055 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2056 This->eax_prop.flEnvironmentDiffusion);
2057 getALError();
2059 This->dirty.bit.effect = 1;
2060 res = DS_OK;
2063 else if(propid == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF)
2065 res = DSERR_INVALIDPARAM;
2066 if(cbPropData >= sizeof(FLOAT))
2068 union {
2069 const void *v;
2070 const FLOAT *fl;
2071 } data = { pPropData };
2073 This->eax_prop.flAirAbsorptionHF = *data.fl;
2074 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2075 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2076 getALError();
2078 This->dirty.bit.effect = 1;
2079 res = DS_OK;
2082 else if(propid == DSPROPERTY_EAXLISTENER_FLAGS)
2084 res = DSERR_INVALIDPARAM;
2085 if(cbPropData >= sizeof(DWORD))
2087 union {
2088 const void *v;
2089 const DWORD *dw;
2090 } data = { pPropData };
2092 This->eax_prop.dwFlags = *data.dw;
2093 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2094 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2095 AL_TRUE : AL_FALSE);
2096 getALError();
2098 This->dirty.bit.effect = 1;
2099 res = DS_OK;
2102 else if(propid != 0)
2103 FIXME("Unhandled propid: 0x%08x\n", propid);
2105 if(res == DS_OK && immediate)
2106 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2108 popALContext();
2109 LeaveCriticalSection(&This->crst);
2111 else
2112 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2114 return res;
2117 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2118 REFGUID guidPropSet, ULONG dwPropID,
2119 PULONG pTypeSupport)
2121 DS8Primary *This = impl_from_IKsPropertySet(iface);
2122 HRESULT res = E_PROP_ID_UNSUPPORTED;
2124 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2126 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2128 EnterCriticalSection(&This->crst);
2130 if(This->effect == 0)
2131 res = E_PROP_ID_UNSUPPORTED;
2132 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2133 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2134 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2135 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2136 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2137 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2138 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2139 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2140 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2142 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2143 res = DS_OK;
2145 else
2146 FIXME("Unhandled propid: 0x%08x\n", dwPropID);
2148 LeaveCriticalSection(&This->crst);
2150 else
2151 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2153 return res;
2156 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2158 DS8PrimaryProp_QueryInterface,
2159 DS8PrimaryProp_AddRef,
2160 DS8PrimaryProp_Release,
2161 DS8PrimaryProp_Get,
2162 DS8PrimaryProp_Set,
2163 DS8PrimaryProp_QuerySupport