Improve some traces
[dsound-openal.git] / primary.c
blob819aabc353570048d632f4929690437ed223ebfc
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);
186 checkALError();
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.DeferUpdatesSOFT = alGetProcAddress("alDeferUpdatesSOFT");
288 This->ExtAL.ProcessUpdatesSOFT = alGetProcAddress("alProcessUpdatesSOFT");
289 This->SupportedExt[SOFT_DEFERRED_UPDATES] = AL_TRUE;
292 if(alcIsExtensionPresent(parent->device, "ALC_EXT_EFX"))
294 #define LOAD_FUNC(x) (This->ExtAL.x = alGetProcAddress("al"#x))
295 LOAD_FUNC(GenEffects);
296 LOAD_FUNC(DeleteEffects);
297 LOAD_FUNC(Effecti);
298 LOAD_FUNC(Effectf);
300 LOAD_FUNC(GenAuxiliaryEffectSlots);
301 LOAD_FUNC(DeleteAuxiliaryEffectSlots);
302 LOAD_FUNC(AuxiliaryEffectSloti);
303 #undef LOAD_FUNC
304 This->SupportedExt[EXT_EFX] = AL_TRUE;
306 This->ExtAL.GenEffects(1, &This->effect);
307 This->ExtAL.Effecti(This->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
309 This->ExtAL.GenAuxiliaryEffectSlots(1, &This->auxslot);
311 This->eax_prop = EnvironmentDefaults[EAX_ENVIRONMENT_GENERIC];
313 wfx->wFormatTag = WAVE_FORMAT_PCM;
314 wfx->nChannels = 2;
315 wfx->wBitsPerSample = 8;
316 wfx->nSamplesPerSec = 22050;
317 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
318 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
319 wfx->cbSize = 0;
321 This->stopped = TRUE;
322 This->parent = parent;
323 /* Apparently primary buffer size is always 32k,
324 * tested on windows with 192k 24 bits sound @ 6 channels
325 * where it will run out in 60 ms and it isn't pointer aligned
327 This->buf_size = 32768;
329 if(!This->SupportedExt[SOFT_BUFFER_SUB_DATA] &&
330 !This->SupportedExt[SOFT_BUFFER_SAMPLES] &&
331 !This->SupportedExt[EXT_STATIC_BUFFER])
333 ERR("Missing alBufferSubDataSOFT, alBufferSamplesSOFT , and alBufferDataStatic on device '%s', sound playback quality may be degraded\n",
334 alcGetString(parent->device, ALC_DEVICE_SPECIFIER));
335 ERR("Please consider using OpenAL-Soft\n");
338 if(This->SupportedExt[SOFT_DEFERRED_UPDATES])
340 This->DeferUpdates = This->ExtAL.DeferUpdatesSOFT;
341 This->ProcessUpdates = This->ExtAL.ProcessUpdatesSOFT;
343 else
345 This->DeferUpdates = wrap_DeferUpdates;
346 This->ProcessUpdates = wrap_ProcessUpdates;
349 /* Make sure DS3DListener defaults are applied to OpenAL */
350 listener = &This->listen;
351 listener->dwSize = sizeof(*listener);
352 listener->vPosition.x = 0.0;
353 listener->vPosition.y = 0.0;
354 listener->vPosition.z = 0.0;
355 listener->vVelocity.x = 0.0;
356 listener->vVelocity.y = 0.0;
357 listener->vVelocity.z = 0.0;
358 listener->vOrientFront.x = 0.0;
359 listener->vOrientFront.y = 0.0;
360 listener->vOrientFront.z = 1.0;
361 listener->vOrientTop.x = 0.0;
362 listener->vOrientTop.y = 1.0;
363 listener->vOrientTop.z = 0.0;
364 listener->flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
365 listener->flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
366 listener->flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
367 hr = IDirectSound3DListener_SetAllParameters(&This->IDirectSound3DListener_iface, listener, DS3D_IMMEDIATE);
368 if(FAILED(hr))
369 ERR("Could not set 3d parameters: %08"LONGFMT"x\n", hr);
371 for(nsources = 0;nsources < sizeof(srcs)/sizeof(*srcs);nsources++)
373 alGenSources(1, &srcs[nsources]);
374 if(alGetError() != AL_NO_ERROR)
375 break;
377 alDeleteSources(nsources, srcs);
378 checkALError();
380 popALContext();
382 This->max_sources = nsources;
383 This->sizenotifies = This->sizebuffers = This->sizesources = nsources+1;
385 hr = DSERR_OUTOFMEMORY;
386 This->sources = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->sources));
387 This->buffers = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->buffers));
388 This->notifies = HeapAlloc(GetProcessHeap(), 0, nsources*sizeof(*This->notifies));
389 if(!This->sources || !This->buffers || !This->notifies)
390 goto fail;
392 This->thread_hdl = CreateThread(NULL, 0, ThreadProc, This, 0, &This->thread_id);
393 if(This->thread_hdl == NULL)
394 goto fail;
396 *ppv = This;
397 return S_OK;
399 fail:
400 DS8Primary_Destroy(This);
401 return hr;
404 void DS8Primary_Destroy(DS8Primary *This)
406 TRACE("Destroying primary %p\n", This);
408 if(This->timer_id)
410 timeKillEvent(This->timer_id);
411 timeEndPeriod(This->timer_res);
412 TRACE("Killed timer\n");
414 if(This->thread_hdl)
416 PostThreadMessageA(This->thread_id, WM_QUIT, 0, 0);
417 if(WaitForSingleObject(This->thread_hdl, 1000) != WAIT_OBJECT_0)
418 ERR("Thread wait timed out");
419 CloseHandle(This->thread_hdl);
422 if(This->ctx)
424 /* Calling setALContext is not appropriate here,
425 * since we *have* to unset the context before destroying it
427 ALCcontext *old_ctx;
429 EnterCriticalSection(&This->crst);
430 EnterCriticalSection(&openal_crst);
431 old_ctx = get_context();
432 if(old_ctx != This->ctx)
433 set_context(This->ctx);
434 else
435 old_ctx = NULL;
437 while(This->nbuffers--)
438 DS8Buffer_Destroy(This->buffers[This->nbuffers]);
440 if(This->nsources)
441 alDeleteSources(This->nsources, This->sources);
443 if(This->effect)
444 This->ExtAL.DeleteEffects(1, &This->effect);
445 if(This->auxslot)
446 This->ExtAL.DeleteAuxiliaryEffectSlots(1, &This->auxslot);
448 HeapFree(GetProcessHeap(), 0, This->sources);
449 HeapFree(GetProcessHeap(), 0, This->notifies);
450 HeapFree(GetProcessHeap(), 0, This->buffers);
452 set_context(old_ctx);
453 alcDestroyContext(This->ctx);
454 LeaveCriticalSection(&openal_crst);
455 LeaveCriticalSection(&This->crst);
458 This->crst.DebugInfo->Spare[0] = 0;
459 DeleteCriticalSection(&This->crst);
461 HeapFree(GetProcessHeap(), 0, This);
464 static inline DS8Primary *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
466 return CONTAINING_RECORD(iface, DS8Primary, IDirectSoundBuffer_iface);
469 static HRESULT WINAPI DS8Primary_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, LPVOID *ppv)
471 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
473 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
475 *ppv = NULL;
476 if(IsEqualIID(riid, &IID_IUnknown) ||
477 IsEqualIID(riid, &IID_IDirectSoundBuffer))
478 *ppv = &This->IDirectSoundBuffer_iface;
479 else if(IsEqualIID(riid, &IID_IDirectSound3DListener))
481 if((This->flags&DSBCAPS_CTRL3D))
482 *ppv = &This->IDirectSound3DListener_iface;
484 else
485 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
487 if(*ppv)
489 IUnknown_AddRef((IUnknown*)*ppv);
490 return S_OK;
493 return E_NOINTERFACE;
496 static ULONG WINAPI DS8Primary_AddRef(IDirectSoundBuffer *iface)
498 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
499 LONG ret;
501 ret = InterlockedIncrement(&This->ref);
502 if(ret == 1) This->flags = 0;
504 return ret;
507 static ULONG WINAPI DS8Primary_Release(IDirectSoundBuffer *iface)
509 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
510 LONG ret;
512 ret = InterlockedDecrement(&This->ref);
514 return ret;
517 static HRESULT WINAPI DS8Primary_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
519 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
521 TRACE("(%p)->(%p)\n", iface, caps);
523 if(!caps || caps->dwSize < sizeof(*caps))
525 WARN("Invalid DSBCAPS (%p, %"LONGFMT"u)\n", caps, caps ? caps->dwSize : 0);
526 return DSERR_INVALIDPARAM;
529 EnterCriticalSection(&This->crst);
530 caps->dwFlags = This->flags;
531 caps->dwBufferBytes = This->buf_size;
532 caps->dwUnlockTransferRate = 0;
533 caps->dwPlayCpuOverhead = 0;
534 LeaveCriticalSection(&This->crst);
536 return DS_OK;
539 static HRESULT WINAPI DS8Primary_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
541 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
542 HRESULT hr = DSERR_PRIOLEVELNEEDED;
544 EnterCriticalSection(&This->crst);
545 if(This->write_emu)
546 hr = IDirectSoundBuffer8_GetCurrentPosition(This->write_emu, playpos, curpos);
547 LeaveCriticalSection(&This->crst);
549 return hr;
552 static HRESULT WINAPI DS8Primary_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
554 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
555 HRESULT hr = S_OK;
556 UINT size;
558 if(!wfx && !written)
560 WARN("Cannot report format or format size\n");
561 return DSERR_INVALIDPARAM;
564 EnterCriticalSection(&This->crst);
565 size = sizeof(This->format.Format) + This->format.Format.cbSize;
566 if(written)
567 *written = size;
568 if(wfx)
570 if(allocated < size)
571 hr = DSERR_INVALIDPARAM;
572 else
573 memcpy(wfx, &This->format.Format, size);
575 LeaveCriticalSection(&This->crst);
577 return hr;
580 static HRESULT WINAPI DS8Primary_GetVolume(IDirectSoundBuffer *iface, LONG *volume)
582 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
583 HRESULT hr = S_OK;
585 TRACE("(%p)->(%p)\n", iface, volume);
587 if(!volume)
588 return DSERR_INVALIDPARAM;
590 EnterCriticalSection(&This->crst);
591 if(!(This->flags & DSBCAPS_CTRLVOLUME))
592 hr = DSERR_CONTROLUNAVAIL;
593 else
595 ALfloat gain;
597 setALContext(This->ctx);
598 alGetListenerf(AL_GAIN, &gain);
599 checkALError();
600 popALContext();
602 *volume = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
604 LeaveCriticalSection(&This->crst);
606 return hr;
609 static HRESULT WINAPI DS8Primary_GetPan(IDirectSoundBuffer *iface, LONG *pan)
611 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
612 HRESULT hr = S_OK;
614 WARN("(%p)->(%p): semi-stub\n", iface, pan);
616 if(!pan)
617 return DSERR_INVALIDPARAM;
619 EnterCriticalSection(&This->crst);
620 if(This->write_emu)
621 hr = IDirectSoundBuffer8_GetPan(This->write_emu, pan);
622 else if(!(This->flags & DSBCAPS_CTRLPAN))
623 hr = DSERR_CONTROLUNAVAIL;
624 else
625 *pan = 0;
626 LeaveCriticalSection(&This->crst);
628 return hr;
631 static HRESULT WINAPI DS8Primary_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
633 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
634 HRESULT hr = S_OK;
636 WARN("(%p)->(%p): semi-stub\n", iface, freq);
638 if(!freq)
639 return DSERR_INVALIDPARAM;
641 EnterCriticalSection(&This->crst);
642 if(!(This->flags & DSBCAPS_CTRLFREQUENCY))
643 hr = DSERR_CONTROLUNAVAIL;
644 else
645 *freq = This->format.Format.nSamplesPerSec;
646 LeaveCriticalSection(&This->crst);
648 return hr;
651 static HRESULT WINAPI DS8Primary_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
653 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
655 TRACE("(%p)->(%p)\n", iface, status);
657 if(!status)
658 return DSERR_INVALIDPARAM;
660 EnterCriticalSection(&This->crst);
662 *status = DSBSTATUS_PLAYING|DSBSTATUS_LOOPING;
663 if((This->flags&DSBCAPS_LOCDEFER))
664 *status |= DSBSTATUS_LOCHARDWARE;
666 if(This->stopped)
668 DWORD i, state;
669 HRESULT hr;
671 for(i = 0;i < This->nbuffers;++i)
673 hr = IDirectSoundBuffer8_GetStatus(&This->buffers[i]->IDirectSoundBuffer8_iface, &state);
674 if(SUCCEEDED(hr) && (state&DSBSTATUS_PLAYING))
675 break;
677 if(i == This->nbuffers)
679 /* Primary stopped and no buffers playing.. */
680 *status = 0;
684 LeaveCriticalSection(&This->crst);
686 return S_OK;
689 static HRESULT WINAPI DS8Primary_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
691 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
692 HRESULT hr = S_OK;
694 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
696 if(!desc || desc->lpwfxFormat || desc->dwBufferBytes)
698 WARN("Bad DSBDESC for primary buffer\n");
699 return DSERR_INVALIDPARAM;
701 if((desc->dwFlags&DSBCAPS_CTRLFX) ||
702 (desc->dwFlags&DSBCAPS_CTRLPOSITIONNOTIFY) ||
703 (desc->dwFlags&DSBCAPS_LOCSOFTWARE))
705 WARN("Bad dwFlags %08"LONGFMT"x\n", desc->dwFlags);
706 return DSERR_INVALIDPARAM;
709 EnterCriticalSection(&This->crst);
710 /* Should be 0 if not initialized */
711 if(This->flags)
713 hr = DSERR_ALREADYINITIALIZED;
714 goto out;
717 if(This->parent->prio_level == DSSCL_WRITEPRIMARY)
719 DSBUFFERDESC emudesc;
720 DS8Buffer *emu;
722 if(This->write_emu)
724 ERR("There shouldn't be a write_emu!\n");
725 IDirectSoundBuffer8_Release(This->write_emu);
726 This->write_emu = NULL;
729 memset(&emudesc, 0, sizeof(emudesc));
730 emudesc.dwSize = sizeof(emudesc);
731 emudesc.dwFlags = DSBCAPS_LOCHARDWARE | (desc->dwFlags&DSBCAPS_CTRLPAN);
732 /* Dont play last incomplete sample */
733 emudesc.dwBufferBytes = This->buf_size - (This->buf_size%This->format.Format.nBlockAlign);
734 emudesc.lpwfxFormat = &This->format.Format;
736 hr = DS8Buffer_Create(&emu, This, NULL);
737 if(SUCCEEDED(hr))
739 This->write_emu = &emu->IDirectSoundBuffer8_iface;
740 hr = IDirectSoundBuffer8_Initialize(This->write_emu, ds, &emudesc);
741 if(FAILED(hr))
743 IDirectSoundBuffer8_Release(This->write_emu);
744 This->write_emu = NULL;
749 if(SUCCEEDED(hr))
750 This->flags = desc->dwFlags | DSBCAPS_LOCHARDWARE;
751 out:
752 LeaveCriticalSection(&This->crst);
753 return hr;
756 static HRESULT WINAPI DS8Primary_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
758 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
759 HRESULT hr = DSERR_PRIOLEVELNEEDED;
761 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %p, %p, %p, %p, %"LONGFMT"u)\n", iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
763 EnterCriticalSection(&This->crst);
764 if(This->write_emu)
765 hr = IDirectSoundBuffer8_Lock(This->write_emu, ofs, bytes, ptr1, len1, ptr2, len2, flags);
766 LeaveCriticalSection(&This->crst);
768 return hr;
771 static HRESULT WINAPI DS8Primary_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD res2, DWORD flags)
773 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
774 HRESULT hr;
776 TRACE("(%p)->(%"LONGFMT"u, %"LONGFMT"u, %"LONGFMT"u)\n", iface, res1, res2, flags);
778 if(!(flags & DSBPLAY_LOOPING))
780 WARN("Flags (%08"LONGFMT"x) not set to DSBPLAY_LOOPING\n", flags);
781 return DSERR_INVALIDPARAM;
784 EnterCriticalSection(&This->crst);
785 hr = S_OK;
786 if(This->write_emu)
787 hr = IDirectSoundBuffer8_Play(This->write_emu, res1, res2, flags);
788 if(SUCCEEDED(hr))
789 This->stopped = FALSE;
790 LeaveCriticalSection(&This->crst);
792 return hr;
795 static HRESULT WINAPI DS8Primary_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
797 WARN("(%p)->(%"LONGFMT"u)\n", iface, pos);
798 return DSERR_INVALIDCALL;
801 /* Just assume the format is crap, and clean up the damage */
802 static void copy_waveformat(WAVEFORMATEX *wfx, const WAVEFORMATEX *from)
804 if(from->wFormatTag == WAVE_FORMAT_PCM)
806 wfx->cbSize = 0;
807 if(from->wBitsPerSample == 8 ||
808 from->wBitsPerSample == 16 ||
809 from->wBitsPerSample == 24 ||
810 from->wBitsPerSample == 32)
811 wfx->wBitsPerSample = from->wBitsPerSample;
813 else if(from->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
815 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)wfx;
816 const WAVEFORMATEXTENSIBLE *fromx = (const WAVEFORMATEXTENSIBLE*)from;
817 DWORD size = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
819 /* Fail silently.. */
820 if(from->cbSize < size)
821 return;
822 if(!fromx->Samples.wValidBitsPerSample &&
823 !fromx->Format.wBitsPerSample)
824 return;
826 if(!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
827 !IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
829 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe->SubFormat));
830 return;
833 wfe->Format.wBitsPerSample = from->wBitsPerSample;
834 wfe->Samples.wValidBitsPerSample = fromx->Samples.wValidBitsPerSample;
835 if(!wfe->Samples.wValidBitsPerSample)
836 wfe->Samples.wValidBitsPerSample = wfe->Format.wBitsPerSample;
837 wfe->Format.cbSize = size;
838 wfe->dwChannelMask = fromx->dwChannelMask;
839 wfe->SubFormat = fromx->SubFormat;
841 else
843 ERR("Unhandled format tag %04x\n", from->wFormatTag);
844 return;
847 if(from->nChannels)
848 wfx->nChannels = from->nChannels;
849 wfx->wFormatTag = from->wFormatTag;
850 if(from->nSamplesPerSec >= DSBFREQUENCY_MIN &&
851 from->nSamplesPerSec <= DSBFREQUENCY_MAX)
852 wfx->nSamplesPerSec = from->nSamplesPerSec;
853 wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
854 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
857 static HRESULT WINAPI DS8Primary_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
859 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
860 HRESULT hr = S_OK;
861 ALCint freq;
863 TRACE("(%p)->(%p)\n", iface, wfx);
865 if(!wfx)
867 WARN("Missing format\n");
868 return DSERR_INVALIDPARAM;
871 EnterCriticalSection(&This->crst);
873 if(This->parent->prio_level < DSSCL_PRIORITY)
875 hr = DSERR_PRIOLEVELNEEDED;
876 goto out;
879 TRACE("Requested primary format:\n"
880 " FormatTag = %04x\n"
881 " Channels = %u\n"
882 " SamplesPerSec = %"LONGFMT"u\n"
883 " AvgBytesPerSec = %"LONGFMT"u\n"
884 " BlockAlign = %u\n"
885 " BitsPerSample = %u\n",
886 wfx->wFormatTag, wfx->nChannels,
887 wfx->nSamplesPerSec, wfx->nAvgBytesPerSec,
888 wfx->nBlockAlign, wfx->wBitsPerSample);
890 copy_waveformat(&This->format.Format, wfx);
892 freq = This->format.Format.nSamplesPerSec;
893 alcGetIntegerv(This->parent->device, ALC_FREQUENCY, 1, &freq);
894 checkALCError(This->parent->device);
896 This->format.Format.nSamplesPerSec = freq;
897 This->format.Format.nAvgBytesPerSec = This->format.Format.nBlockAlign *
898 This->format.Format.nSamplesPerSec;
900 if(This->write_emu)
902 DS8Buffer *buf;
903 DSBUFFERDESC desc;
905 memset(&desc, 0, sizeof(desc));
906 desc.dwSize = sizeof(desc);
907 desc.dwFlags = DSBCAPS_LOCHARDWARE|DSBCAPS_CTRLPAN;
908 desc.dwBufferBytes = This->buf_size - (This->buf_size % This->format.Format.nBlockAlign);
909 desc.lpwfxFormat = &This->format.Format;
911 hr = DS8Buffer_Create(&buf, This, NULL);
912 if(FAILED(hr))
913 goto out;
915 hr = IDirectSoundBuffer8_Initialize(&buf->IDirectSoundBuffer8_iface, &This->parent->IDirectSound_iface, &desc);
916 if(FAILED(hr))
917 DS8Buffer_Destroy(buf);
918 else
920 IDirectSoundBuffer8_Release(This->write_emu);
921 This->write_emu = &buf->IDirectSoundBuffer8_iface;
925 out:
926 LeaveCriticalSection(&This->crst);
927 return hr;
930 static HRESULT WINAPI DS8Primary_SetVolume(IDirectSoundBuffer *iface, LONG vol)
932 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
933 HRESULT hr = S_OK;
935 TRACE("(%p)->(%"LONGFMT"d)\n", iface, vol);
937 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
939 WARN("Invalid volume (%"LONGFMT"d)\n", vol);
940 return DSERR_INVALIDPARAM;
943 EnterCriticalSection(&This->crst);
944 if(!(This->flags&DSBCAPS_CTRLVOLUME))
945 hr = DSERR_CONTROLUNAVAIL;
946 if(SUCCEEDED(hr))
948 setALContext(This->ctx);
949 alListenerf(AL_GAIN, mB_to_gain(vol));
950 popALContext();
952 LeaveCriticalSection(&This->crst);
954 return hr;
957 static HRESULT WINAPI DS8Primary_SetPan(IDirectSoundBuffer *iface, LONG pan)
959 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
960 HRESULT hr;
962 TRACE("(%p)->(%"LONGFMT"d)\n", iface, pan);
964 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
966 WARN("invalid parameter: pan = %"LONGFMT"d\n", pan);
967 return DSERR_INVALIDPARAM;
970 EnterCriticalSection(&This->crst);
971 if(!(This->flags&DSBCAPS_CTRLPAN))
973 WARN("control unavailable\n");
974 hr = DSERR_CONTROLUNAVAIL;
976 else if(This->write_emu)
977 hr = IDirectSoundBuffer8_SetPan(This->write_emu, pan);
978 else
980 FIXME("Not supported\n");
981 hr = E_NOTIMPL;
983 LeaveCriticalSection(&This->crst);
985 return hr;
988 static HRESULT WINAPI DS8Primary_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
990 WARN("(%p)->(%"LONGFMT"u)\n", iface, freq);
991 return DSERR_CONTROLUNAVAIL;
994 static HRESULT WINAPI DS8Primary_Stop(IDirectSoundBuffer *iface)
996 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
997 HRESULT hr = S_OK;
999 TRACE("(%p)->()\n", iface);
1001 EnterCriticalSection(&This->crst);
1002 if(This->write_emu)
1003 hr = IDirectSoundBuffer8_Stop(This->write_emu);
1004 if(SUCCEEDED(hr))
1005 This->stopped = TRUE;
1006 LeaveCriticalSection(&This->crst);
1008 return hr;
1011 static HRESULT WINAPI DS8Primary_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1013 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1014 HRESULT hr = DSERR_INVALIDCALL;
1016 TRACE("(%p)->(%p, %"LONGFMT"u, %p, %"LONGFMT"u)\n", iface, ptr1, len1, ptr2, len2);
1018 EnterCriticalSection(&This->crst);
1019 if(This->write_emu)
1020 hr = IDirectSoundBuffer8_Unlock(This->write_emu, ptr1, len1, ptr2, len2);
1021 LeaveCriticalSection(&This->crst);
1023 return hr;
1026 static HRESULT WINAPI DS8Primary_Restore(IDirectSoundBuffer *iface)
1028 DS8Primary *This = impl_from_IDirectSoundBuffer(iface);
1029 HRESULT hr = S_OK;
1031 TRACE("(%p)->()\n", iface);
1033 EnterCriticalSection(&This->crst);
1034 if(This->write_emu)
1035 hr = IDirectSoundBuffer8_Restore(This->write_emu);
1036 LeaveCriticalSection(&This->crst);
1038 return hr;
1041 static const IDirectSoundBufferVtbl DS8Primary_Vtbl =
1043 DS8Primary_QueryInterface,
1044 DS8Primary_AddRef,
1045 DS8Primary_Release,
1046 DS8Primary_GetCaps,
1047 DS8Primary_GetCurrentPosition,
1048 DS8Primary_GetFormat,
1049 DS8Primary_GetVolume,
1050 DS8Primary_GetPan,
1051 DS8Primary_GetFrequency,
1052 DS8Primary_GetStatus,
1053 DS8Primary_Initialize,
1054 DS8Primary_Lock,
1055 DS8Primary_Play,
1056 DS8Primary_SetCurrentPosition,
1057 DS8Primary_SetFormat,
1058 DS8Primary_SetVolume,
1059 DS8Primary_SetPan,
1060 DS8Primary_SetFrequency,
1061 DS8Primary_Stop,
1062 DS8Primary_Unlock,
1063 DS8Primary_Restore
1066 static inline DS8Primary *impl_from_IDirectSound3DListener(IDirectSound3DListener *iface)
1068 return CONTAINING_RECORD(iface, DS8Primary, IDirectSound3DListener_iface);
1071 static HRESULT WINAPI DS8Primary3D_QueryInterface(IDirectSound3DListener *iface, REFIID riid, void **ppv)
1073 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1074 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1077 static ULONG WINAPI DS8Primary3D_AddRef(IDirectSound3DListener *iface)
1079 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1080 LONG ret;
1082 ret = InterlockedIncrement(&This->ds3d_ref);
1083 TRACE("new refcount %"LONGFMT"d\n", ret);
1085 return ret;
1089 /* Considering the primary buffer doesn't get destroyed
1090 * it doesn't make sense to destroy ds3d here
1092 static ULONG WINAPI DS8Primary3D_Release(IDirectSound3DListener *iface)
1094 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1095 LONG ret;
1097 ret = InterlockedDecrement(&This->ds3d_ref);
1098 TRACE("new refcount %"LONGFMT"d\n", ret);
1100 return ret;
1104 static HRESULT WINAPI DS8Primary3D_GetAllParameters(IDirectSound3DListener *iface, DS3DLISTENER *listener)
1106 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1108 TRACE("(%p)->(%p)\n", iface, listener);
1110 if(!listener || listener->dwSize < sizeof(*listener))
1112 WARN("Invalid DS3DLISTENER %p %"LONGFMT"u\n", listener, listener ? listener->dwSize : 0);
1113 return DSERR_INVALIDPARAM;
1116 EnterCriticalSection(&This->crst);
1117 setALContext(This->ctx);
1118 IDirectSound3DListener_GetPosition(iface, &listener->vPosition);
1119 IDirectSound3DListener_GetVelocity(iface, &listener->vVelocity);
1120 IDirectSound3DListener_GetOrientation(iface, &listener->vOrientFront, &listener->vOrientTop);
1121 IDirectSound3DListener_GetDistanceFactor(iface, &listener->flDistanceFactor);
1122 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flRolloffFactor);
1123 IDirectSound3DListener_GetRolloffFactor(iface, &listener->flDopplerFactor);
1124 popALContext();
1125 LeaveCriticalSection(&This->crst);
1127 return DS_OK;
1130 static HRESULT WINAPI DS8Primary3D_GetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE *distancefactor)
1132 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1134 TRACE("(%p)->(%p)\n", iface, distancefactor);
1136 if(!distancefactor)
1138 WARN("Invalid parameter %p\n", distancefactor);
1139 return DSERR_INVALIDPARAM;
1142 EnterCriticalSection(&This->crst);
1143 setALContext(This->ctx);
1145 *distancefactor = 343.3f/alGetFloat(AL_SPEED_OF_SOUND);
1146 checkALError();
1148 popALContext();
1149 LeaveCriticalSection(&This->crst);
1151 return S_OK;
1154 static HRESULT WINAPI DS8Primary3D_GetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE *dopplerfactor)
1156 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1158 TRACE("(%p)->(%p)\n", iface, dopplerfactor);
1160 if(!dopplerfactor)
1162 WARN("Invalid parameter %p\n", dopplerfactor);
1163 return DSERR_INVALIDPARAM;
1166 EnterCriticalSection(&This->crst);
1167 setALContext(This->ctx);
1169 *dopplerfactor = alGetFloat(AL_DOPPLER_FACTOR);
1170 checkALError();
1172 popALContext();
1173 LeaveCriticalSection(&This->crst);
1175 return S_OK;
1178 static HRESULT WINAPI DS8Primary3D_GetOrientation(IDirectSound3DListener *iface, D3DVECTOR *front, D3DVECTOR *top)
1180 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1181 ALfloat orient[6];
1183 TRACE("(%p)->(%p, %p)\n", iface, front, top);
1185 if(!front || !top)
1187 WARN("Invalid parameter %p %p\n", front, top);
1188 return DSERR_INVALIDPARAM;
1191 EnterCriticalSection(&This->crst);
1192 setALContext(This->ctx);
1194 alGetListenerfv(AL_ORIENTATION, orient);
1195 checkALError();
1197 front->x = orient[0];
1198 front->y = orient[1];
1199 front->z = -orient[2];
1200 top->x = orient[3];
1201 top->y = orient[4];
1202 top->z = -orient[5];
1204 popALContext();
1205 LeaveCriticalSection(&This->crst);
1207 return S_OK;
1210 static HRESULT WINAPI DS8Primary3D_GetPosition(IDirectSound3DListener *iface, D3DVECTOR *pos)
1212 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1213 ALfloat alpos[3];
1215 TRACE("(%p)->(%p)\n", iface, pos);
1217 if(!pos)
1219 WARN("Invalid parameter %p\n", pos);
1220 return DSERR_INVALIDPARAM;
1223 EnterCriticalSection(&This->crst);
1224 setALContext(This->ctx);
1226 alGetListenerfv(AL_POSITION, alpos);
1227 checkALError();
1229 pos->x = alpos[0];
1230 pos->y = alpos[1];
1231 pos->z = -alpos[2];
1233 popALContext();
1234 LeaveCriticalSection(&This->crst);
1236 return S_OK;
1239 static HRESULT WINAPI DS8Primary3D_GetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE *rollofffactor)
1241 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1243 TRACE("(%p)->(%p)\n", iface, rollofffactor);
1245 if(!rollofffactor)
1247 WARN("Invalid parameter %p\n", rollofffactor);
1248 return DSERR_INVALIDPARAM;
1251 EnterCriticalSection(&This->crst);
1252 *rollofffactor = This->rollofffactor;
1253 LeaveCriticalSection(&This->crst);
1255 return S_OK;
1258 static HRESULT WINAPI DS8Primary3D_GetVelocity(IDirectSound3DListener *iface, D3DVECTOR *velocity)
1260 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1261 ALfloat vel[3];
1263 TRACE("(%p)->(%p)\n", iface, velocity);
1265 if(!velocity)
1267 WARN("Invalid parameter %p\n", velocity);
1268 return DSERR_INVALIDPARAM;
1271 EnterCriticalSection(&This->crst);
1272 setALContext(This->ctx);
1274 alGetListenerfv(AL_VELOCITY, vel);
1275 checkALError();
1277 velocity->x = vel[0];
1278 velocity->y = vel[1];
1279 velocity->z = -vel[2];
1281 popALContext();
1282 LeaveCriticalSection(&This->crst);
1284 return S_OK;
1287 static HRESULT WINAPI DS8Primary3D_SetAllParameters(IDirectSound3DListener *iface, const DS3DLISTENER *listen, DWORD apply)
1289 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1291 TRACE("(%p)->(%p, %"LONGFMT"u)\n", iface, listen, apply);
1293 if(!listen || listen->dwSize < sizeof(*listen))
1295 WARN("Invalid parameter %p %"LONGFMT"u\n", listen, listen ? listen->dwSize : 0);
1296 return DSERR_INVALIDPARAM;
1299 if(listen->flDistanceFactor > DS3D_MAXDISTANCEFACTOR ||
1300 listen->flDistanceFactor < DS3D_MINDISTANCEFACTOR)
1302 WARN("Invalid distance factor (%f)\n", listen->flDistanceFactor);
1303 return DSERR_INVALIDPARAM;
1306 if(listen->flDopplerFactor > DS3D_MAXDOPPLERFACTOR ||
1307 listen->flDopplerFactor < DS3D_MINDOPPLERFACTOR)
1309 WARN("Invalid doppler factor (%f)\n", listen->flDopplerFactor);
1310 return DSERR_INVALIDPARAM;
1313 if(listen->flRolloffFactor < DS3D_MINROLLOFFFACTOR ||
1314 listen->flRolloffFactor > DS3D_MAXROLLOFFFACTOR)
1316 WARN("Invalid rolloff factor (%f)\n", listen->flRolloffFactor);
1317 return DSERR_INVALIDPARAM;
1320 EnterCriticalSection(&This->crst);
1321 setALContext(This->ctx);
1322 IDirectSound3DListener_SetPosition(iface, listen->vPosition.x, listen->vPosition.y, listen->vPosition.z, apply);
1323 IDirectSound3DListener_SetVelocity(iface, listen->vVelocity.x, listen->vVelocity.y, listen->vVelocity.z, apply);
1324 IDirectSound3DListener_SetOrientation(iface, listen->vOrientFront.x, listen->vOrientFront.y, listen->vOrientFront.z,
1325 listen->vOrientTop.x, listen->vOrientTop.y, listen->vOrientTop.z, apply);
1326 IDirectSound3DListener_SetDistanceFactor(iface, listen->flDistanceFactor, apply);
1327 IDirectSound3DListener_SetRolloffFactor(iface, listen->flRolloffFactor, apply);
1328 IDirectSound3DListener_SetDopplerFactor(iface, listen->flDopplerFactor, apply);
1329 popALContext();
1330 LeaveCriticalSection(&This->crst);
1332 return S_OK;
1335 static HRESULT WINAPI DS8Primary3D_SetDistanceFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1337 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1339 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1341 if(factor < DS3D_MINDISTANCEFACTOR ||
1342 factor > DS3D_MAXDISTANCEFACTOR)
1344 WARN("Invalid parameter %f\n", factor);
1345 return DSERR_INVALIDPARAM;
1348 EnterCriticalSection(&This->crst);
1349 if(apply == DS3D_DEFERRED)
1351 This->listen.flDistanceFactor = factor;
1352 This->dirty.bit.distancefactor = 1;
1354 else
1356 setALContext(This->ctx);
1357 alSpeedOfSound(343.3f/factor);
1358 if(This->SupportedExt[EXT_EFX])
1359 alListenerf(AL_METERS_PER_UNIT, factor);
1360 checkALError();
1361 popALContext();
1363 LeaveCriticalSection(&This->crst);
1365 return S_OK;
1368 static HRESULT WINAPI DS8Primary3D_SetDopplerFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1370 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1372 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1374 if(factor < DS3D_MINDOPPLERFACTOR ||
1375 factor > DS3D_MAXDOPPLERFACTOR)
1377 WARN("Invalid parameter %f\n", factor);
1378 return DSERR_INVALIDPARAM;
1381 EnterCriticalSection(&This->crst);
1382 if(apply == DS3D_DEFERRED)
1384 This->listen.flDopplerFactor = factor;
1385 This->dirty.bit.dopplerfactor = 1;
1387 else
1389 setALContext(This->ctx);
1390 alDopplerFactor(factor);
1391 checkALError();
1392 popALContext();
1394 LeaveCriticalSection(&This->crst);
1396 return S_OK;
1399 static HRESULT WINAPI DS8Primary3D_SetOrientation(IDirectSound3DListener *iface, D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply)
1401 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1403 TRACE("(%p)->(%f, %f, %f, %f, %f, %f, %"LONGFMT"u)\n", iface, xFront, yFront, zFront, xTop, yTop, zTop, apply);
1405 EnterCriticalSection(&This->crst);
1406 if(apply == DS3D_DEFERRED)
1408 This->listen.vOrientFront.x = xFront;
1409 This->listen.vOrientFront.y = yFront;
1410 This->listen.vOrientFront.z = zFront;
1411 This->listen.vOrientTop.x = xTop;
1412 This->listen.vOrientTop.y = yTop;
1413 This->listen.vOrientTop.z = zTop;
1414 This->dirty.bit.orientation = 1;
1416 else
1418 ALfloat orient[6] = {
1419 xFront, yFront, -zFront,
1420 xTop, yTop, -zTop
1422 setALContext(This->ctx);
1423 alListenerfv(AL_ORIENTATION, orient);
1424 checkALError();
1425 popALContext();
1427 LeaveCriticalSection(&This->crst);
1429 return S_OK;
1432 static HRESULT WINAPI DS8Primary3D_SetPosition(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1434 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1436 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1438 EnterCriticalSection(&This->crst);
1439 if(apply == DS3D_DEFERRED)
1441 This->listen.vPosition.x = x;
1442 This->listen.vPosition.y = y;
1443 This->listen.vPosition.z = z;
1444 This->dirty.bit.pos = 1;
1446 else
1448 setALContext(This->ctx);
1449 alListener3f(AL_POSITION, x, y, -z);
1450 checkALError();
1451 popALContext();
1453 LeaveCriticalSection(&This->crst);
1455 return S_OK;
1458 static HRESULT WINAPI DS8Primary3D_SetRolloffFactor(IDirectSound3DListener *iface, D3DVALUE factor, DWORD apply)
1460 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1462 TRACE("(%p)->(%f, %"LONGFMT"u)\n", iface, factor, apply);
1464 if(factor < DS3D_MINROLLOFFFACTOR ||
1465 factor > DS3D_MAXROLLOFFFACTOR)
1467 WARN("Invalid parameter %f\n", factor);
1468 return DSERR_INVALIDPARAM;
1471 EnterCriticalSection(&This->crst);
1472 if(apply == DS3D_DEFERRED)
1474 This->listen.flRolloffFactor = factor;
1475 This->dirty.bit.rollofffactor = 1;
1477 else
1479 DWORD i;
1481 setALContext(This->ctx);
1482 for(i = 0;i < This->nbuffers;++i)
1484 if(This->buffers[i]->ds3dmode != DS3DMODE_DISABLE)
1485 alSourcef(This->buffers[i]->source, AL_ROLLOFF_FACTOR, factor);
1487 checkALError();
1488 popALContext();
1490 This->rollofffactor = factor;
1492 LeaveCriticalSection(&This->crst);
1494 return S_OK;
1497 static HRESULT WINAPI DS8Primary3D_SetVelocity(IDirectSound3DListener *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1499 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1501 TRACE("(%p)->(%f, %f, %f, %"LONGFMT"u)\n", iface, x, y, z, apply);
1503 EnterCriticalSection(&This->crst);
1504 if(apply == DS3D_DEFERRED)
1506 This->listen.vVelocity.x = x;
1507 This->listen.vVelocity.y = y;
1508 This->listen.vVelocity.z = z;
1509 This->dirty.bit.vel = 1;
1511 else
1513 setALContext(This->ctx);
1514 alListener3f(AL_VELOCITY, x, y, -z);
1515 checkALError();
1516 popALContext();
1518 LeaveCriticalSection(&This->crst);
1520 return S_OK;
1523 static HRESULT WINAPI DS8Primary3D_CommitDeferredSettings(IDirectSound3DListener *iface)
1525 DS8Primary *This = impl_from_IDirectSound3DListener(iface);
1526 const DS3DLISTENER *listen = &This->listen;
1527 DWORD i;
1529 EnterCriticalSection(&This->crst);
1530 setALContext(This->ctx);
1531 This->DeferUpdates();
1533 if(This->dirty.bit.pos)
1534 alListener3f(AL_POSITION, listen->vPosition.x, listen->vPosition.y, -listen->vPosition.z);
1535 if(This->dirty.bit.vel)
1536 alListener3f(AL_VELOCITY, listen->vVelocity.x, listen->vVelocity.y, -listen->vVelocity.z);
1537 if(This->dirty.bit.orientation)
1539 ALfloat orient[6] = {
1540 listen->vOrientFront.x, listen->vOrientFront.y, -listen->vOrientFront.z,
1541 listen->vOrientTop.x, listen->vOrientTop.y, -listen->vOrientTop.z
1543 alListenerfv(AL_ORIENTATION, orient);
1545 if(This->dirty.bit.distancefactor)
1547 alSpeedOfSound(343.3f/listen->flDistanceFactor);
1548 if(This->SupportedExt[EXT_EFX])
1549 alListenerf(AL_METERS_PER_UNIT, listen->flDistanceFactor);
1552 if(This->dirty.bit.rollofffactor)
1554 ALfloat rolloff = This->rollofffactor;
1555 for(i = 0;i < This->nbuffers;++i)
1557 DS8Buffer *buf = This->buffers[i];
1558 if(buf->ds3dmode != DS3DMODE_DISABLE)
1559 alSourcef(buf->source, AL_ROLLOFF_FACTOR, rolloff);
1563 if(This->dirty.bit.dopplerfactor)
1564 alDopplerFactor(listen->flDopplerFactor);
1566 if(This->dirty.bit.effect)
1567 This->ExtAL.AuxiliaryEffectSloti(This->auxslot, AL_EFFECTSLOT_EFFECT, This->effect);
1569 /* checkALError is here for debugging */
1570 checkALError();
1572 TRACE("Dirty flags was: 0x%02x\n", This->dirty.flags);
1573 This->dirty.flags = 0;
1575 for(i = 0;i < This->nbuffers;++i)
1577 DS8Buffer *buf = This->buffers[i];
1579 if(!buf->dirty.flags)
1580 continue;
1582 if(buf->dirty.bit.pos)
1583 alSource3f(buf->source, AL_POSITION,
1584 buf->ds3dbuffer.vPosition.x,
1585 buf->ds3dbuffer.vPosition.y,
1586 -buf->ds3dbuffer.vPosition.z);
1587 if(buf->dirty.bit.vel)
1588 alSource3f(buf->source, AL_VELOCITY,
1589 buf->ds3dbuffer.vVelocity.x,
1590 buf->ds3dbuffer.vVelocity.y,
1591 -buf->ds3dbuffer.vVelocity.z);
1592 if(buf->dirty.bit.cone_angles)
1594 alSourcei(buf->source, AL_CONE_INNER_ANGLE,
1595 buf->ds3dbuffer.dwInsideConeAngle);
1596 alSourcei(buf->source, AL_CONE_OUTER_ANGLE,
1597 buf->ds3dbuffer.dwOutsideConeAngle);
1599 if(buf->dirty.bit.cone_orient)
1600 alSource3f(buf->source, AL_DIRECTION,
1601 buf->ds3dbuffer.vConeOrientation.x,
1602 buf->ds3dbuffer.vConeOrientation.y,
1603 -buf->ds3dbuffer.vConeOrientation.z);
1604 if(buf->dirty.bit.cone_outsidevolume)
1605 alSourcef(buf->source, AL_CONE_OUTER_GAIN,
1606 mB_to_gain(buf->ds3dbuffer.lConeOutsideVolume));
1607 if(buf->dirty.bit.min_distance)
1608 alSourcef(buf->source, AL_REFERENCE_DISTANCE, buf->ds3dbuffer.flMinDistance);
1609 if(buf->dirty.bit.max_distance)
1610 alSourcef(buf->source, AL_MAX_DISTANCE, buf->ds3dbuffer.flMaxDistance);
1611 if(buf->dirty.bit.mode)
1613 buf->ds3dmode = buf->ds3dbuffer.dwMode;
1614 alSourcei(buf->source, AL_SOURCE_RELATIVE,
1615 (buf->ds3dmode!=DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
1616 alSourcef(buf->source, AL_ROLLOFF_FACTOR,
1617 (buf->ds3dmode==DS3DMODE_DISABLE) ? 0.0f : This->rollofffactor);
1619 buf->dirty.flags = 0;
1621 checkALError();
1623 This->ProcessUpdates();
1624 popALContext();
1625 LeaveCriticalSection(&This->crst);
1627 return S_OK;
1630 static const IDirectSound3DListenerVtbl DS8Primary3D_Vtbl =
1632 DS8Primary3D_QueryInterface,
1633 DS8Primary3D_AddRef,
1634 DS8Primary3D_Release,
1635 DS8Primary3D_GetAllParameters,
1636 DS8Primary3D_GetDistanceFactor,
1637 DS8Primary3D_GetDopplerFactor,
1638 DS8Primary3D_GetOrientation,
1639 DS8Primary3D_GetPosition,
1640 DS8Primary3D_GetRolloffFactor,
1641 DS8Primary3D_GetVelocity,
1642 DS8Primary3D_SetAllParameters,
1643 DS8Primary3D_SetDistanceFactor,
1644 DS8Primary3D_SetDopplerFactor,
1645 DS8Primary3D_SetOrientation,
1646 DS8Primary3D_SetPosition,
1647 DS8Primary3D_SetRolloffFactor,
1648 DS8Primary3D_SetVelocity,
1649 DS8Primary3D_CommitDeferredSettings
1652 /* NOTE: Although the app handles listener properties through secondary buffers,
1653 * we pass the requests to the primary buffer though a propertyset interface.
1654 * These methods are not exposed to the app. */
1655 static inline DS8Primary *impl_from_IKsPropertySet(IKsPropertySet *iface)
1657 return CONTAINING_RECORD(iface, DS8Primary, IKsPropertySet_iface);
1660 static HRESULT WINAPI DS8PrimaryProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
1662 DS8Primary *This = impl_from_IKsPropertySet(iface);
1663 return DS8Primary_QueryInterface(&This->IDirectSoundBuffer_iface, riid, ppv);
1666 static ULONG WINAPI DS8PrimaryProp_AddRef(IKsPropertySet *iface)
1668 DS8Primary *This = impl_from_IKsPropertySet(iface);
1669 LONG ret;
1671 ret = InterlockedIncrement(&This->prop_ref);
1672 TRACE("new refcount %"LONGFMT"d\n", ret);
1674 return ret;
1677 static ULONG WINAPI DS8PrimaryProp_Release(IKsPropertySet *iface)
1679 DS8Primary *This = impl_from_IKsPropertySet(iface);
1680 LONG ret;
1682 ret = InterlockedDecrement(&This->prop_ref);
1683 TRACE("new refcount %"LONGFMT"d\n", ret);
1685 return ret;
1688 static HRESULT WINAPI DS8PrimaryProp_Get(IKsPropertySet *iface,
1689 REFGUID guidPropSet, ULONG dwPropID,
1690 LPVOID pInstanceData, ULONG cbInstanceData,
1691 LPVOID pPropData, ULONG cbPropData,
1692 PULONG pcbReturned)
1694 DS8Primary *This = impl_from_IKsPropertySet(iface);
1695 HRESULT res = E_PROP_ID_UNSUPPORTED;
1696 (void)pInstanceData;
1697 (void)cbInstanceData;
1699 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1701 EnterCriticalSection(&This->crst);
1703 if(This->effect == 0)
1704 res = E_PROP_ID_UNSUPPORTED;
1705 else switch(dwPropID)
1707 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1708 res = DSERR_INVALIDPARAM;
1709 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1711 union {
1712 void *v;
1713 EAXLISTENERPROPERTIES *props;
1714 } data = { pPropData };
1716 *data.props = This->eax_prop;
1717 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
1718 res = DS_OK;
1720 break;
1722 case DSPROPERTY_EAXLISTENER_ROOM:
1723 res = DSERR_INVALIDPARAM;
1724 if(cbPropData >= sizeof(LONG))
1726 union {
1727 void *v;
1728 LONG *l;
1729 } data = { pPropData };
1731 *data.l = This->eax_prop.lRoom;
1732 *pcbReturned = sizeof(LONG);
1733 res = DS_OK;
1735 break;
1736 case DSPROPERTY_EAXLISTENER_ROOMHF:
1737 res = DSERR_INVALIDPARAM;
1738 if(cbPropData >= sizeof(LONG))
1740 union {
1741 void *v;
1742 LONG *l;
1743 } data = { pPropData };
1745 *data.l = This->eax_prop.lRoomHF;
1746 *pcbReturned = sizeof(LONG);
1747 res = DS_OK;
1749 break;
1751 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1752 res = DSERR_INVALIDPARAM;
1753 if(cbPropData >= sizeof(FLOAT))
1755 union {
1756 void *v;
1757 FLOAT *fl;
1758 } data = { pPropData };
1760 *data.fl = This->eax_prop.flRoomRolloffFactor;
1761 *pcbReturned = sizeof(FLOAT);
1762 res = DS_OK;
1764 break;
1766 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1767 res = DSERR_INVALIDPARAM;
1768 if(cbPropData >= sizeof(DWORD))
1770 union {
1771 void *v;
1772 DWORD *dw;
1773 } data = { pPropData };
1775 *data.dw = This->eax_prop.dwEnvironment;
1776 *pcbReturned = sizeof(DWORD);
1777 res = DS_OK;
1779 break;
1781 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
1782 res = DSERR_INVALIDPARAM;
1783 if(cbPropData >= sizeof(FLOAT))
1785 union {
1786 void *v;
1787 FLOAT *fl;
1788 } data = { pPropData };
1790 *data.fl = This->eax_prop.flEnvironmentSize;
1791 *pcbReturned = sizeof(FLOAT);
1792 res = DS_OK;
1794 break;
1795 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
1796 res = DSERR_INVALIDPARAM;
1797 if(cbPropData >= sizeof(FLOAT))
1799 union {
1800 void *v;
1801 FLOAT *fl;
1802 } data = { pPropData };
1804 *data.fl = This->eax_prop.flEnvironmentDiffusion;
1805 *pcbReturned = sizeof(FLOAT);
1806 res = DS_OK;
1808 break;
1810 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
1811 res = DSERR_INVALIDPARAM;
1812 if(cbPropData >= sizeof(FLOAT))
1814 union {
1815 void *v;
1816 FLOAT *fl;
1817 } data = { pPropData };
1819 *data.fl = This->eax_prop.flAirAbsorptionHF;
1820 *pcbReturned = sizeof(FLOAT);
1821 res = DS_OK;
1823 break;
1825 case DSPROPERTY_EAXLISTENER_FLAGS:
1826 res = DSERR_INVALIDPARAM;
1827 if(cbPropData >= sizeof(DWORD))
1829 union {
1830 void *v;
1831 DWORD *dw;
1832 } data = { pPropData };
1834 *data.dw = This->eax_prop.dwFlags;
1835 *pcbReturned = sizeof(DWORD);
1836 res = DS_OK;
1838 break;
1840 default:
1841 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
1842 break;
1845 LeaveCriticalSection(&This->crst);
1847 else
1848 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
1850 return res;
1853 static HRESULT WINAPI DS8PrimaryProp_Set(IKsPropertySet *iface,
1854 REFGUID guidPropSet, ULONG dwPropID,
1855 LPVOID pInstanceData, ULONG cbInstanceData,
1856 LPVOID pPropData, ULONG cbPropData)
1858 DS8Primary *This = impl_from_IKsPropertySet(iface);
1859 HRESULT res = E_PROP_ID_UNSUPPORTED;
1860 (void)pInstanceData;
1861 (void)cbInstanceData;
1863 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
1865 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
1866 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
1868 EnterCriticalSection(&This->crst);
1869 setALContext(This->ctx);
1871 if(This->effect == 0)
1872 res = E_PROP_ID_UNSUPPORTED;
1873 else switch(propid)
1875 case 0: /* 0 = not setting any property, just apply */
1876 res = DS_OK;
1877 break;
1879 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
1880 do_allparams:
1881 res = DSERR_INVALIDPARAM;
1882 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
1884 union {
1885 const void *v;
1886 const EAXLISTENERPROPERTIES *props;
1887 } data = { pPropData };
1889 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
1890 This->eax_prop = *data.props;
1891 This->ExtAL.Effectf(This->effect, AL_REVERB_DENSITY,
1892 (data.props->flEnvironmentSize < 2.0f) ?
1893 (data.props->flEnvironmentSize - 1.0f) : 1.0f);
1894 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
1895 data.props->flEnvironmentDiffusion);
1897 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1898 mB_to_gain(data.props->lRoom));
1899 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1900 mB_to_gain(data.props->lRoomHF));
1902 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1903 data.props->flRoomRolloffFactor);
1905 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_TIME,
1906 data.props->flDecayTime);
1907 This->ExtAL.Effectf(This->effect, AL_REVERB_DECAY_HFRATIO,
1908 data.props->flDecayHFRatio);
1910 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_GAIN,
1911 mB_to_gain(data.props->lReflections));
1912 This->ExtAL.Effectf(This->effect, AL_REVERB_REFLECTIONS_DELAY,
1913 data.props->flReflectionsDelay);
1915 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_GAIN,
1916 mB_to_gain(data.props->lReverb));
1917 This->ExtAL.Effectf(This->effect, AL_REVERB_LATE_REVERB_DELAY,
1918 data.props->flReverbDelay);
1920 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
1921 mB_to_gain(data.props->flAirAbsorptionHF));
1923 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
1924 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
1925 AL_TRUE : AL_FALSE);
1927 checkALError();
1929 This->dirty.bit.effect = 1;
1930 res = DS_OK;
1932 break;
1934 case DSPROPERTY_EAXLISTENER_ROOM:
1935 res = DSERR_INVALIDPARAM;
1936 if(cbPropData >= sizeof(LONG))
1938 union {
1939 const void *v;
1940 const LONG *l;
1941 } data = { pPropData };
1943 This->eax_prop.lRoom = *data.l;
1944 This->ExtAL.Effectf(This->effect, AL_REVERB_GAIN,
1945 mB_to_gain(This->eax_prop.lRoom));
1946 checkALError();
1948 This->dirty.bit.effect = 1;
1949 res = DS_OK;
1951 break;
1952 case DSPROPERTY_EAXLISTENER_ROOMHF:
1953 res = DSERR_INVALIDPARAM;
1954 if(cbPropData >= sizeof(LONG))
1956 union {
1957 const void *v;
1958 const LONG *l;
1959 } data = { pPropData };
1961 This->eax_prop.lRoomHF = *data.l;
1962 This->ExtAL.Effectf(This->effect, AL_REVERB_GAINHF,
1963 mB_to_gain(This->eax_prop.lRoomHF));
1964 checkALError();
1966 This->dirty.bit.effect = 1;
1967 res = DS_OK;
1969 break;
1971 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
1972 res = DSERR_INVALIDPARAM;
1973 if(cbPropData >= sizeof(FLOAT))
1975 union {
1976 const void *v;
1977 const FLOAT *fl;
1978 } data = { pPropData };
1980 This->eax_prop.flRoomRolloffFactor = *data.fl;
1981 This->ExtAL.Effectf(This->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
1982 This->eax_prop.flRoomRolloffFactor);
1983 checkALError();
1985 This->dirty.bit.effect = 1;
1986 res = DS_OK;
1988 break;
1990 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
1991 res = DSERR_INVALIDPARAM;
1992 if(cbPropData >= sizeof(DWORD))
1994 union {
1995 const void *v;
1996 const DWORD *dw;
1997 } data = { pPropData };
1999 if(*data.dw < EAX_ENVIRONMENT_COUNT)
2001 /* Get the environment index's default and pass it down to
2002 * ALLPARAMETERS */
2003 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2004 pPropData = (void*)&EnvironmentDefaults[*data.dw];
2005 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
2006 goto do_allparams;
2009 break;
2011 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2012 res = DSERR_INVALIDPARAM;
2013 if(cbPropData >= sizeof(FLOAT))
2015 union {
2016 const void *v;
2017 const FLOAT *fl;
2018 } data = { pPropData };
2020 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2022 double scale = (*data.fl)/This->eax_prop.flEnvironmentSize;
2024 This->eax_prop.flEnvironmentSize = *data.fl;
2026 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2028 This->eax_prop.flDecayTime *= scale;
2029 This->eax_prop.flDecayTime = clampF(This->eax_prop.flDecayTime, 0.1f, 20.0f);
2031 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2033 This->eax_prop.lReflections += gain_to_mB(1.0/scale);
2034 This->eax_prop.lReflections = clampI(This->eax_prop.lReflections, -10000, 1000);
2036 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2038 This->eax_prop.flReflectionsDelay *= scale;
2039 This->eax_prop.flReflectionsDelay = clampF(This->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2041 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2043 This->eax_prop.lReverb += gain_to_mB(1.0/scale);
2044 This->eax_prop.lReverb = clampI(This->eax_prop.lReverb, -10000, 2000);
2046 if((This->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2048 This->eax_prop.flReverbDelay *= scale;
2049 This->eax_prop.flReverbDelay = clampF(This->eax_prop.flReverbDelay, 0.0f, 0.1f);
2052 /* Pass the updated environment properties down to ALLPARAMETERS */
2053 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2054 pPropData = (void*)&This->eax_prop;
2055 cbPropData = sizeof(This->eax_prop);
2056 goto do_allparams;
2059 break;
2060 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2061 res = DSERR_INVALIDPARAM;
2062 if(cbPropData >= sizeof(FLOAT))
2064 union {
2065 const void *v;
2066 const FLOAT *fl;
2067 } data = { pPropData };
2069 This->eax_prop.flEnvironmentDiffusion = *data.fl;
2070 This->ExtAL.Effectf(This->effect, AL_REVERB_DIFFUSION,
2071 This->eax_prop.flEnvironmentDiffusion);
2072 checkALError();
2074 This->dirty.bit.effect = 1;
2075 res = DS_OK;
2077 break;
2079 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2080 res = DSERR_INVALIDPARAM;
2081 if(cbPropData >= sizeof(FLOAT))
2083 union {
2084 const void *v;
2085 const FLOAT *fl;
2086 } data = { pPropData };
2088 This->eax_prop.flAirAbsorptionHF = *data.fl;
2089 This->ExtAL.Effectf(This->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2090 mB_to_gain(This->eax_prop.flAirAbsorptionHF));
2091 checkALError();
2093 This->dirty.bit.effect = 1;
2094 res = DS_OK;
2096 break;
2098 case DSPROPERTY_EAXLISTENER_FLAGS:
2099 res = DSERR_INVALIDPARAM;
2100 if(cbPropData >= sizeof(DWORD))
2102 union {
2103 const void *v;
2104 const DWORD *dw;
2105 } data = { pPropData };
2107 This->eax_prop.dwFlags = *data.dw;
2108 This->ExtAL.Effecti(This->effect, AL_REVERB_DECAY_HFLIMIT,
2109 (This->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2110 AL_TRUE : AL_FALSE);
2111 checkALError();
2113 This->dirty.bit.effect = 1;
2114 res = DS_OK;
2116 default:
2117 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", propid);
2118 break;
2121 if(res == DS_OK && immediate)
2122 IDirectSound3DListener_CommitDeferredSettings(&This->IDirectSound3DListener_iface);
2124 popALContext();
2125 LeaveCriticalSection(&This->crst);
2127 else
2128 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2130 return res;
2133 static HRESULT WINAPI DS8PrimaryProp_QuerySupport(IKsPropertySet *iface,
2134 REFGUID guidPropSet, ULONG dwPropID,
2135 PULONG pTypeSupport)
2137 DS8Primary *This = impl_from_IKsPropertySet(iface);
2138 HRESULT res = E_PROP_ID_UNSUPPORTED;
2140 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2142 EnterCriticalSection(&This->crst);
2144 if(This->effect == 0)
2145 res = E_PROP_ID_UNSUPPORTED;
2146 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2147 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2148 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2149 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2150 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2151 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2152 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2153 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2154 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2156 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2157 res = DS_OK;
2159 else
2160 FIXME("Unhandled propid: 0x%08"LONGFMT"x\n", dwPropID);
2162 LeaveCriticalSection(&This->crst);
2164 else
2165 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2167 return res;
2170 static const IKsPropertySetVtbl DS8PrimaryProp_Vtbl =
2172 DS8PrimaryProp_QueryInterface,
2173 DS8PrimaryProp_AddRef,
2174 DS8PrimaryProp_Release,
2175 DS8PrimaryProp_Get,
2176 DS8PrimaryProp_Set,
2177 DS8PrimaryProp_QuerySupport