Compare the default device's GUID instead of its pointer
[dsound-openal.git] / buffer.c
blob1fa8100fd4dc07ae0eeacb1a0d848439b21395d3
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 #define CONST_VTABLE
24 #include <stdarg.h>
25 #include <string.h>
27 #define INITGUID
28 #include "windows.h"
29 #include "dsound.h"
30 #include "mmsystem.h"
31 #include "ks.h"
32 #include <devpropdef.h>
34 #include "dsound_private.h"
37 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e,0xdf1c,0x4efd,0x80,0x20,0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
39 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
41 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
43 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
44 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 #ifndef DS_INCOMPLETE
47 #define DS_INCOMPLETE ((HRESULT)0x08780020)
48 #endif
50 #ifndef WAVE_FORMAT_IEEE_FLOAT
51 #define WAVE_FORMAT_IEEE_FLOAT 3
52 #endif
55 /* TODO: when bufferlost is set, return from all calls except initialize with
56 * DSERR_BUFFERLOST
58 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
59 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
60 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
61 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
64 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
66 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
69 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
71 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
74 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
76 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
79 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
81 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
84 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
86 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
90 /* Should be called with critsect held and context set.. */
91 static void DS8Buffer_addnotify(DS8Buffer *buf)
93 DS8Primary *prim = buf->primary;
94 DS8Buffer **list;
95 DWORD i;
97 list = prim->notifies;
98 for(i = 0; i < prim->nnotifies; ++i)
100 if(buf == list[i])
102 ERR("Buffer %p already in notification list\n", buf);
103 return;
106 if(prim->nnotifies == prim->sizenotifies)
108 list = HeapReAlloc(GetProcessHeap(), 0, list, (prim->nnotifies + 1) * sizeof(*list));
109 if(!list) return;
110 prim->sizenotifies++;
112 list[prim->nnotifies++] = buf;
113 prim->notifies = list;
117 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
119 out->Format = *format;
120 out->Format.cbSize = 0;
122 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
123 !BITFIELD_TEST(prim->Exts, EXT_MCFORMATS))
125 WARN("Multi-channel not available\n");
126 return NULL;
129 if(format->wBitsPerSample == 8)
131 switch(format->nChannels)
133 case 1: return "AL_FORMAT_MONO8";
134 case 2: return "AL_FORMAT_STEREO8";
135 case 4: return "AL_FORMAT_QUAD8";
136 case 6: return "AL_FORMAT_51CHN8";
137 case 7: return "AL_FORMAT_61CHN8";
138 case 8: return "AL_FORMAT_71CHN8";
141 else if(format->wBitsPerSample == 16)
143 switch(format->nChannels)
145 case 1: return "AL_FORMAT_MONO16";
146 case 2: return "AL_FORMAT_STEREO16";
147 case 4: return "AL_FORMAT_QUAD16";
148 case 6: return "AL_FORMAT_51CHN16";
149 case 7: return "AL_FORMAT_61CHN16";
150 case 8: return "AL_FORMAT_71CHN16";
154 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
155 format->wBitsPerSample, format->nChannels);
156 return NULL;
159 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
161 out->Format = *format;
162 out->Format.cbSize = 0;
164 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
165 !BITFIELD_TEST(prim->Exts, EXT_MCFORMATS))
167 WARN("Multi-channel not available\n");
168 return NULL;
171 if(format->wBitsPerSample == 32 && BITFIELD_TEST(prim->Exts, EXT_FLOAT32))
173 switch(format->nChannels)
175 case 1: return "AL_FORMAT_MONO_FLOAT32";
176 case 2: return "AL_FORMAT_STEREO_FLOAT32";
177 case 4: return "AL_FORMAT_QUAD32";
178 case 6: return "AL_FORMAT_51CHN32";
179 case 7: return "AL_FORMAT_61CHN32";
180 case 8: return "AL_FORMAT_71CHN32";
184 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
185 format->wBitsPerSample, format->nChannels);
186 return NULL;
189 /* Speaker configs */
190 #define MONO SPEAKER_FRONT_CENTER
191 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
192 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
193 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
194 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
195 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
196 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
198 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
200 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
201 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
203 if(!out->Samples.wValidBitsPerSample)
204 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
205 else if(out->Samples.wValidBitsPerSample > out->Format.wBitsPerSample)
207 WARN("Invalid ValidBitsPerSample (%u > %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
208 return NULL;
210 else if(out->Samples.wValidBitsPerSample < out->Format.wBitsPerSample)
212 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
213 return NULL;
216 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
217 !BITFIELD_TEST(prim->Exts, EXT_MCFORMATS))
219 WARN("Multi-channel not available\n");
220 return NULL;
223 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
225 if(out->Samples.wValidBitsPerSample == 8)
227 switch(out->dwChannelMask)
229 case MONO: return "AL_FORMAT_MONO8";
230 case STEREO: return "AL_FORMAT_STEREO8";
231 case REAR: return "AL_FORMAT_REAR8";
232 case QUAD: return "AL_FORMAT_QUAD8";
233 case X5DOT1: return "AL_FORMAT_51CHN8";
234 case X6DOT1: return "AL_FORMAT_61CHN8";
235 case X7DOT1: return "AL_FORMAT_71CHN8";
238 else if(out->Samples.wValidBitsPerSample == 16)
240 switch(out->dwChannelMask)
242 case MONO: return "AL_FORMAT_MONO16";
243 case STEREO: return "AL_FORMAT_STEREO16";
244 case REAR: return "AL_FORMAT_REAR16";
245 case QUAD: return "AL_FORMAT_QUAD16";
246 case X5DOT1: return "AL_FORMAT_51CHN16";
247 case X6DOT1: return "AL_FORMAT_61CHN16";
248 case X7DOT1: return "AL_FORMAT_71CHN16";
252 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#lx)\n",
253 out->Samples.wValidBitsPerSample, out->dwChannelMask);
254 return NULL;
256 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
257 BITFIELD_TEST(prim->Exts, EXT_FLOAT32))
259 if(out->Samples.wValidBitsPerSample == 32)
261 switch(out->dwChannelMask)
263 case MONO: return "AL_FORMAT_MONO_FLOAT32";
264 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
265 case REAR: return "AL_FORMAT_REAR32";
266 case QUAD: return "AL_FORMAT_QUAD32";
267 case X5DOT1: return "AL_FORMAT_51CHN32";
268 case X6DOT1: return "AL_FORMAT_61CHN32";
269 case X7DOT1: return "AL_FORMAT_71CHN32";
272 else
274 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
275 return NULL;
278 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
279 out->Samples.wValidBitsPerSample, out->dwChannelMask);
280 return NULL;
282 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
283 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
284 return NULL;
287 static void DS8Data_Release(DS8Data *This);
288 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
290 HRESULT hr = DSERR_INVALIDPARAM;
291 const WAVEFORMATEX *format;
292 const char *fmt_str = NULL;
293 DS8Data *pBuffer;
294 DWORD buf_size;
296 format = desc->lpwfxFormat;
297 TRACE("Requested buffer format:\n"
298 " FormatTag = 0x%04x\n"
299 " Channels = %d\n"
300 " SamplesPerSec = %lu\n"
301 " AvgBytesPerSec = %lu\n"
302 " BlockAlign = %d\n"
303 " BitsPerSample = %d\n",
304 format->wFormatTag, format->nChannels,
305 format->nSamplesPerSec, format->nAvgBytesPerSec,
306 format->nBlockAlign, format->wBitsPerSample);
308 if(format->nChannels <= 0)
310 WARN("Invalid Channels %d\n", format->nChannels);
311 return DSERR_INVALIDPARAM;
313 if(format->nSamplesPerSec < DSBFREQUENCY_MIN || format->nSamplesPerSec > DSBFREQUENCY_MAX)
315 WARN("Invalid SamplesPerSec %lu\n", format->nSamplesPerSec);
316 return DSERR_INVALIDPARAM;
318 if(format->nBlockAlign <= 0)
320 WARN("Invalid BlockAlign %d\n", format->nBlockAlign);
321 return DSERR_INVALIDPARAM;
323 if(format->wBitsPerSample == 0 || (format->wBitsPerSample%8) != 0)
325 WARN("Invalid BitsPerSample %d\n", format->wBitsPerSample);
326 return DSERR_INVALIDPARAM;
328 if(format->nBlockAlign != format->nChannels*format->wBitsPerSample/8)
330 WARN("Invalid BlockAlign %d (expected %u = %u*%u/8)\n",
331 format->nBlockAlign, format->nChannels*format->wBitsPerSample/8,
332 format->nChannels, format->wBitsPerSample);
333 return DSERR_INVALIDPARAM;
335 if(format->nAvgBytesPerSec != format->nBlockAlign*format->nSamplesPerSec)
337 WARN("Invalid AvgBytesPerSec %lu (expected %lu = %lu*%u)\n",
338 format->nAvgBytesPerSec, format->nSamplesPerSec*format->nBlockAlign,
339 format->nSamplesPerSec, format->nBlockAlign);
340 return DSERR_INVALIDPARAM;
343 if((desc->dwFlags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
345 WARN("Hardware and software location requested\n");
346 return DSERR_INVALIDPARAM;
349 buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
350 buf_size -= buf_size%format->nBlockAlign;
351 if(buf_size < DSBSIZE_MIN) return DSERR_BUFFERTOOSMALL;
352 if(buf_size > DSBSIZE_MAX) return DSERR_INVALIDPARAM;
354 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
355 * will need the EAX-RAM extension. Currently, we just tell the app it
356 * gets what it wanted. */
357 if(!BITFIELD_TEST(prim->Exts, SOFTX_MAP_BUFFER))
358 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer)+buf_size);
359 else
360 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
361 if(!pBuffer) return E_OUTOFMEMORY;
362 pBuffer->ref = 1;
363 pBuffer->primary = prim;
365 pBuffer->dsbflags = desc->dwFlags;
366 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
367 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
368 pBuffer->buf_size = buf_size;
370 if(format->wFormatTag == WAVE_FORMAT_PCM)
371 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
372 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
373 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
374 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
376 const WAVEFORMATEXTENSIBLE *wfe;
378 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
379 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
380 goto fail;
382 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
383 TRACE("Extensible values:\n"
384 " Samples = %d\n"
385 " ChannelMask = 0x%lx\n"
386 " SubFormat = %s\n",
387 wfe->Samples.wReserved, wfe->dwChannelMask,
388 debugstr_guid(&wfe->SubFormat));
390 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
392 else
393 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
394 if(!fmt_str) goto fail;
396 alGetError();
397 pBuffer->buf_format = alGetEnumValue(fmt_str);
398 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
399 pBuffer->buf_format == -1)
401 WARN("Could not get OpenAL format from %s\n", fmt_str);
402 goto fail;
405 hr = E_OUTOFMEMORY;
406 if(!BITFIELD_TEST(prim->Exts, SOFTX_MAP_BUFFER))
408 pBuffer->data = (BYTE*)(pBuffer+1);
410 alGenBuffers(1, &pBuffer->bid);
411 checkALError();
413 else
415 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
416 AL_MAP_PERSISTENT_BIT_SOFT;
417 alGenBuffers(1, &pBuffer->bid);
418 alBufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
419 pBuffer->format.Format.nSamplesPerSec, map_bits);
420 pBuffer->data = alMapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
421 checkALError();
423 if(!pBuffer->data) goto fail;
426 *ppv = pBuffer;
427 return S_OK;
429 fail:
430 DS8Data_Release(pBuffer);
431 return hr;
434 static void DS8Data_AddRef(DS8Data *data)
436 InterlockedIncrement(&data->ref);
439 /* This function is always called with the device lock held */
440 static void DS8Data_Release(DS8Data *This)
442 if(InterlockedDecrement(&This->ref)) return;
444 TRACE("Deleting %p\n", This);
445 if(This->bid)
447 DS8Primary *prim = This->primary;
448 if(BITFIELD_TEST(prim->Exts, SOFTX_MAP_BUFFER))
449 alUnmapBufferSOFT(This->bid);
450 alDeleteBuffers(1, &This->bid);
451 checkALError();
453 HeapFree(GetProcessHeap(), 0, This);
457 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig, BOOL prim_emu)
459 DS8Buffer *This = NULL;
460 HRESULT hr;
461 DWORD i;
463 *ppv = NULL;
464 EnterCriticalSection(prim->crst);
465 if(prim_emu)
467 This = &prim->writable_buf;
468 memset(This, 0, sizeof(*This));
470 else for(i = 0;i < prim->NumBufferGroups;++i)
472 if(prim->BufferGroups[i].FreeBuffers)
474 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
475 This = prim->BufferGroups[i].Buffers + idx;
476 memset(This, 0, sizeof(*This));
477 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
478 break;
481 LeaveCriticalSection(prim->crst);
482 if(!This)
484 WARN("Out of buffers\n");
485 return DSERR_ALLOCATED;
488 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
489 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
490 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
491 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
493 This->primary = prim;
494 This->ctx = prim->ctx;
495 This->crst = prim->crst;
496 This->ref = This->all_ref = 1;
498 if(orig)
500 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
501 hr = DSERR_BUFFERLOST;
502 if(org->bufferlost)
503 goto fail;
504 DS8Data_AddRef(org->buffer);
505 This->buffer = org->buffer;
508 /* Disable until initialized.. */
509 This->ds3dmode = DS3DMODE_DISABLE;
511 *ppv = This;
512 return DS_OK;
514 fail:
515 DS8Buffer_Destroy(This);
516 return hr;
519 void DS8Buffer_Destroy(DS8Buffer *This)
521 DS8Primary *prim = This->primary;
522 DWORD i;
524 if(!prim) return;
525 TRACE("Destroying %p\n", This);
527 EnterCriticalSection(prim->crst);
528 /* Remove from list, if in list */
529 for(i = 0;i < prim->nnotifies;++i)
531 if(This == prim->notifies[i])
533 prim->notifies[i] = prim->notifies[--prim->nnotifies];
534 break;
538 setALContext(This->ctx);
539 if(This->source)
541 alSourceStop(This->source);
542 alSourcei(This->source, AL_BUFFER, 0);
543 checkALError();
545 prim->sources->ids[prim->sources->avail_num++] = This->source;
546 This->source = 0;
548 if(This->stream_bids[0])
549 alDeleteBuffers(QBUFFERS, This->stream_bids);
550 if(This->filter[0])
551 alDeleteFilters(2, This->filter);
553 if(This->buffer)
554 DS8Data_Release(This->buffer);
556 popALContext();
558 HeapFree(GetProcessHeap(), 0, This->notify);
560 for(i = 0;i < prim->NumBufferGroups;++i)
562 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
563 if(idx < 64)
565 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
566 This = NULL;
567 break;
570 LeaveCriticalSection(prim->crst);
574 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
576 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
578 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
580 *ppv = NULL;
581 if(IsEqualIID(riid, &IID_IUnknown))
582 *ppv = &This->IDirectSoundBuffer8_iface;
583 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
584 *ppv = &This->IDirectSoundBuffer8_iface;
585 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
587 if(This->primary->parent->is_8)
588 *ppv = &This->IDirectSoundBuffer8_iface;
590 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
592 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
593 *ppv = &This->IDirectSound3DBuffer_iface;
595 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
597 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
598 *ppv = &This->IDirectSoundNotify_iface;
600 else if(IsEqualIID(riid, &IID_IKsPropertySet))
601 *ppv = &This->IKsPropertySet_iface;
602 else
603 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
605 if(*ppv)
607 IUnknown_AddRef((IUnknown*)*ppv);
608 return S_OK;
611 return E_NOINTERFACE;
614 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
616 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
617 LONG ret;
619 InterlockedIncrement(&This->all_ref);
620 ret = InterlockedIncrement(&This->ref);
621 TRACE("new refcount %ld\n", ret);
623 return ret;
626 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
628 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
629 LONG ret;
631 ret = InterlockedDecrement(&This->ref);
632 TRACE("new refcount %ld\n", ret);
633 if(InterlockedDecrement(&This->all_ref) == 0)
634 DS8Buffer_Destroy(This);
636 return ret;
639 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
641 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
643 TRACE("(%p)->(%p)\n", iface, caps);
645 if(!caps || caps->dwSize < sizeof(*caps))
647 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
648 return DSERR_INVALIDPARAM;
651 caps->dwFlags = This->buffer->dsbflags;
652 caps->dwBufferBytes = This->buffer->buf_size;
653 caps->dwUnlockTransferRate = 4096;
654 caps->dwPlayCpuOverhead = 0;
655 return S_OK;
658 HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
660 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
661 ALsizei writecursor, pos;
662 DS8Data *data;
664 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
666 data = This->buffer;
667 if(This->segsize != 0)
669 ALint queued = QBUFFERS;
670 ALint status = 0;
671 ALint ofs = 0;
673 EnterCriticalSection(This->crst);
675 setALContext(This->ctx);
676 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
677 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
678 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
679 checkALError();
680 popALContext();
682 if(status == AL_STOPPED)
683 pos = This->segsize*queued + This->queue_base;
684 else
685 pos = ofs + This->queue_base;
686 if(pos >= data->buf_size)
688 if(This->islooping)
689 pos %= data->buf_size;
690 else if(This->isplaying)
692 pos = data->buf_size;
693 alSourceStop(This->source);
694 alSourcei(This->source, AL_BUFFER, 0);
695 This->curidx = 0;
696 This->isplaying = FALSE;
699 if(This->isplaying)
700 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
701 else
702 writecursor = pos % data->buf_size;
704 LeaveCriticalSection(This->crst);
706 else
708 const WAVEFORMATEX *format = &data->format.Format;
709 ALint status = 0;
710 ALint ofs = 0;
712 setALContext(This->ctx);
713 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
714 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
715 checkALError();
716 popALContext();
718 /* AL_STOPPED means the source naturally reached its end, where
719 * DirectSound's position should be at the end (OpenAL reports a 0
720 * position). The Stop method correlates to pausing, which would put
721 * the source into an AL_PAUSED state and hold its current position.
723 pos = (status == AL_STOPPED) ? data->buf_size : ofs;
724 if(status == AL_PLAYING)
726 writecursor = format->nSamplesPerSec / This->primary->refresh;
727 writecursor *= format->nBlockAlign;
729 else
730 writecursor = 0;
731 writecursor = (writecursor + pos) % data->buf_size;
733 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
735 if(pos > data->buf_size)
737 ERR("playpos > buf_size\n");
738 pos %= data->buf_size;
740 if(writecursor >= data->buf_size)
742 ERR("writepos >= buf_size\n");
743 writecursor %= data->buf_size;
746 if(playpos) *playpos = pos;
747 if(curpos) *curpos = writecursor;
749 return S_OK;
752 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
754 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
755 HRESULT hr = S_OK;
756 UINT size;
758 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
760 if(!wfx && !written)
762 WARN("Cannot report format or format size\n");
763 return DSERR_INVALIDPARAM;
766 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
767 if(wfx)
769 if(allocated < size)
770 hr = DSERR_INVALIDPARAM;
771 else
772 memcpy(wfx, &This->buffer->format.Format, size);
774 if(written)
775 *written = size;
777 return hr;
780 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
782 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
783 HRESULT hr;
785 TRACE("(%p)->(%p)\n", iface, vol);
787 if(!vol)
789 WARN("Invalid pointer\n");
790 return DSERR_INVALIDPARAM;
793 hr = DSERR_CONTROLUNAVAIL;
794 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
795 WARN("Volume control not set\n");
796 else
798 ALfloat gain = 1.0f;
800 setALContext(This->ctx);
801 alGetSourcef(This->source, AL_GAIN, &gain);
802 checkALError();
803 popALContext();
805 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
806 hr = DS_OK;
809 return hr;
812 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
814 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
815 HRESULT hr;
817 TRACE("(%p)->(%p)\n", iface, pan);
819 if(!pan)
821 WARN("Invalid pointer\n");
822 return DSERR_INVALIDPARAM;
825 hr = DSERR_CONTROLUNAVAIL;
826 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
827 WARN("Panning control not set\n");
828 else
830 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
831 *pan = 0;
832 else
834 ALfloat pos[3];
836 setALContext(This->ctx);
837 alGetSourcefv(This->source, AL_POSITION, pos);
838 checkALError();
839 popALContext();
841 *pan = clampI((LONG)((pos[0]+0.5f)*(DSBPAN_RIGHT-DSBPAN_LEFT) + 0.5f) + DSBPAN_LEFT,
842 DSBPAN_LEFT, DSBPAN_RIGHT);
844 hr = DS_OK;
847 return hr;
850 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
852 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
853 HRESULT hr;
855 TRACE("(%p)->(%p)\n", iface, freq);
857 if(!freq)
859 WARN("Invalid pointer\n");
860 return DSERR_INVALIDPARAM;
863 hr = DSERR_CONTROLUNAVAIL;
864 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
865 WARN("Frequency control not set\n");
866 else
868 ALfloat pitch = 1.0f;
870 setALContext(This->ctx);
871 alGetSourcefv(This->source, AL_PITCH, &pitch);
872 checkALError();
873 popALContext();
875 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
876 hr = DS_OK;
879 return hr;
882 HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
884 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
885 ALint state, looping;
887 TRACE("(%p)->(%p)\n", iface, status);
889 if(!status)
891 WARN("Invalid pointer\n");
892 return DSERR_INVALIDPARAM;
894 *status = 0;
896 if(This->segsize == 0)
898 setALContext(This->ctx);
899 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
900 alGetSourcei(This->source, AL_LOOPING, &looping);
901 checkALError();
902 popALContext();
904 else
906 EnterCriticalSection(This->crst);
907 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
908 looping = This->islooping;
909 LeaveCriticalSection(This->crst);
912 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
914 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
915 *status |= DSBSTATUS_LOCSOFTWARE;
916 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
917 *status |= DSBSTATUS_LOCHARDWARE;
919 if(state == AL_PLAYING)
920 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
922 TRACE("%p status = 0x%08lx\n", This, *status);
923 return S_OK;
926 HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
928 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
929 EAX20BUFFERPROPERTIES *eaxbuffer;
930 DS3DBUFFER *ds3dbuffer;
931 DS8Primary *prim;
932 DS8Data *data;
933 HRESULT hr;
935 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
937 EnterCriticalSection(This->crst);
938 setALContext(This->ctx);
940 hr = DSERR_ALREADYINITIALIZED;
941 if(This->source) goto out;
943 prim = This->primary;
944 if(!This->buffer)
946 hr = DSERR_INVALIDPARAM;
947 if(!desc)
949 WARN("Missing DSound buffer description\n");
950 goto out;
952 if(!desc->lpwfxFormat)
954 WARN("Missing buffer format (%p)\n", This);
955 goto out;
957 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
959 if(prim->parent->is_8)
961 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
962 * buffers */
963 WARN("Can't create multi-channel 3D buffers\n");
964 goto out;
966 else
968 static int once = 0;
969 if(!once++)
970 ERR("Multi-channel 3D sounds are not spatialized\n");
973 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
975 static int once = 0;
976 if(!once++)
977 ERR("Panning for multi-channel buffers is not supported\n");
980 hr = DS8Data_Create(&This->buffer, desc, prim);
981 if(FAILED(hr)) goto out;
983 data = This->buffer;
984 if(data->format.Format.wBitsPerSample == 8)
985 memset(data->data, 0x80, data->buf_size);
986 else
987 memset(data->data, 0x00, data->buf_size);
990 data = This->buffer;
991 if(!(data->dsbflags&DSBCAPS_STATIC) && !BITFIELD_TEST(prim->Exts, SOFTX_MAP_BUFFER))
993 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
994 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
995 This->segsize += data->format.Format.nBlockAlign - 1;
996 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
998 alGenBuffers(QBUFFERS, This->stream_bids);
999 checkALError();
1002 hr = DSERR_ALLOCATED;
1003 if(!prim->sources->avail_num)
1004 goto out;
1006 This->source = prim->sources->ids[--(prim->sources->avail_num)];
1007 alSourceRewind(This->source);
1008 alSourcef(This->source, AL_GAIN, 1.0f);
1009 alSourcef(This->source, AL_PITCH, 1.0f);
1010 checkALError();
1012 ds3dbuffer = &This->params;
1013 ds3dbuffer->dwSize = sizeof(This->params);
1014 ds3dbuffer->vPosition.x = 0.0f;
1015 ds3dbuffer->vPosition.y = 0.0f;
1016 ds3dbuffer->vPosition.z = 0.0f;
1017 ds3dbuffer->vVelocity.x = 0.0f;
1018 ds3dbuffer->vVelocity.y = 0.0f;
1019 ds3dbuffer->vVelocity.z = 0.0f;
1020 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1021 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1022 ds3dbuffer->vConeOrientation.x = 0.0f;
1023 ds3dbuffer->vConeOrientation.y = 0.0f;
1024 ds3dbuffer->vConeOrientation.z = 1.0f;
1025 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1026 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1027 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1028 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1029 eaxbuffer = &This->eax_prop;
1030 eaxbuffer->lDirect = 0;
1031 eaxbuffer->lDirectHF = 0;
1032 eaxbuffer->lRoom = 0;
1033 eaxbuffer->lRoomHF = 0;
1034 eaxbuffer->flRoomRolloffFactor = 0.0f;
1035 eaxbuffer->lObstruction = 0;
1036 eaxbuffer->flObstructionLFRatio = 0.25f;
1037 eaxbuffer->lOcclusion = 0;
1038 eaxbuffer->flOcclusionLFRatio = 0.25f;
1039 eaxbuffer->flOcclusionRoomRatio = 0.5f;
1040 eaxbuffer->lOutsideVolumeHF = 0;
1041 eaxbuffer->flAirAbsorptionFactor = 0.0f;
1042 eaxbuffer->dwFlags = EAXBUFFERFLAGS_DIRECTHFAUTO | EAXBUFFERFLAGS_ROOMAUTO |
1043 EAXBUFFERFLAGS_ROOMHFAUTO;
1045 if((data->dsbflags&DSBCAPS_CTRL3D))
1047 union BufferParamFlags dirty = { 0 };
1049 if(BITFIELD_TEST(prim->Exts, EXT_EFX))
1051 alGenFilters(2, This->filter);
1052 alFilteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1053 alFilteri(This->filter[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1056 dirty.bit.pos = 1;
1057 dirty.bit.vel = 1;
1058 dirty.bit.cone_angles = 1;
1059 dirty.bit.cone_orient = 1;
1060 dirty.bit.cone_outsidevolume = 1;
1061 dirty.bit.min_distance = 1;
1062 dirty.bit.max_distance = 1;
1063 dirty.bit.mode = 1;
1064 if(BITFIELD_TEST(prim->Exts, EXT_EFX))
1066 dirty.bit.dry_filter = 1;
1067 dirty.bit.wet_filter = 1;
1068 dirty.bit.room_rolloff = 1;
1069 dirty.bit.cone_outsidevolumehf = 1;
1070 dirty.bit.air_absorb = 1;
1071 dirty.bit.flags = 1;
1073 DS8Buffer_SetParams(This, ds3dbuffer, eaxbuffer, dirty.flags);
1074 checkALError();
1076 else
1078 ALuint source = This->source;
1080 /* Non-3D sources aren't distance attenuated */
1081 This->ds3dmode = DS3DMODE_DISABLE;
1082 alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
1083 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1084 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1085 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1086 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1087 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1088 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1089 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1090 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1091 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1092 if(BITFIELD_TEST(prim->Exts, EXT_EFX))
1094 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f);
1095 alSourcef(source, AL_CONE_OUTER_GAINHF, 1.0f);
1096 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f);
1097 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO, AL_TRUE);
1098 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
1099 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
1100 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
1101 alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);
1103 if(BITFIELD_TEST(prim->Exts, SOFT_SOURCE_SPATIALIZE))
1105 /* Set to auto so panning works for mono, and multi-channel works
1106 * as expected.
1108 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_AUTO_SOFT);
1110 checkALError();
1112 hr = S_OK;
1114 out:
1115 popALContext();
1116 LeaveCriticalSection(This->crst);
1118 return hr;
1121 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1123 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1124 DWORD remain;
1126 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1128 if(!ptr1 || !len1)
1130 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1131 return DSERR_INVALIDPARAM;
1134 *ptr1 = NULL;
1135 *len1 = 0;
1136 if(ptr2) *ptr2 = NULL;
1137 if(len2) *len2 = 0;
1139 if((flags&DSBLOCK_FROMWRITECURSOR))
1140 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1141 else if(ofs >= (DWORD)This->buffer->buf_size)
1143 WARN("Invalid ofs %lu\n", ofs);
1144 return DSERR_INVALIDPARAM;
1146 if((flags&DSBLOCK_ENTIREBUFFER))
1147 bytes = This->buffer->buf_size;
1148 else if(bytes > (DWORD)This->buffer->buf_size)
1150 WARN("Invalid size %lu\n", bytes);
1151 return DSERR_INVALIDPARAM;
1154 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1156 WARN("Already locked\n");
1157 return DSERR_INVALIDPARAM;
1160 *ptr1 = This->buffer->data + ofs;
1161 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1163 *len1 = This->buffer->buf_size - ofs;
1164 remain = bytes - *len1;
1166 else
1168 *len1 = bytes;
1169 remain = 0;
1172 if(ptr2 && len2 && remain)
1174 *ptr2 = This->buffer->data;
1175 *len2 = remain;
1178 return DS_OK;
1181 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1183 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1184 ALint state = AL_STOPPED;
1185 DS8Data *data;
1186 HRESULT hr;
1188 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1190 EnterCriticalSection(This->crst);
1191 setALContext(This->ctx);
1193 hr = DSERR_BUFFERLOST;
1194 if(This->bufferlost)
1196 WARN("Buffer %p lost\n", This);
1197 goto out;
1200 data = This->buffer;
1201 if((data->dsbflags&DSBCAPS_LOCDEFER))
1203 if(!(data->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1205 if(flags & DSBPLAY_LOCSOFTWARE)
1206 data->dsbflags |= DSBCAPS_LOCSOFTWARE;
1207 else
1208 data->dsbflags |= DSBCAPS_LOCHARDWARE;
1211 else if(prio)
1213 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1214 hr = DSERR_INVALIDPARAM;
1215 goto out;
1218 if(This->segsize != 0)
1220 This->islooping = !!(flags&DSBPLAY_LOOPING);
1221 if(This->isplaying) state = AL_PLAYING;
1223 else
1225 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1226 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1228 checkALError();
1230 hr = S_OK;
1231 if(state == AL_PLAYING)
1232 goto out;
1234 if(This->segsize == 0)
1236 if(state != AL_PAUSED)
1237 alSourcei(This->source, AL_BUFFER, data->bid);
1238 alSourcePlay(This->source);
1240 else
1242 alSourceRewind(This->source);
1243 alSourcei(This->source, AL_BUFFER, 0);
1244 This->queue_base = This->data_offset % data->buf_size;
1245 This->curidx = 0;
1247 if(alGetError() != AL_NO_ERROR)
1249 ERR("Couldn't start source\n");
1250 alSourcei(This->source, AL_BUFFER, 0);
1251 checkALError();
1252 hr = DSERR_GENERIC;
1253 goto out;
1255 This->isplaying = TRUE;
1256 This->playflags = flags;
1258 if(This->nnotify)
1259 DS8Buffer_addnotify(This);
1261 out:
1262 popALContext();
1263 LeaveCriticalSection(This->crst);
1264 return hr;
1267 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1269 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1270 DS8Data *data;
1272 TRACE("(%p)->(%lu)\n", iface, pos);
1274 data = This->buffer;
1275 if(pos >= (DWORD)data->buf_size)
1276 return DSERR_INVALIDPARAM;
1277 pos -= pos%data->format.Format.nBlockAlign;
1279 EnterCriticalSection(This->crst);
1281 if(This->segsize != 0)
1283 if(This->isplaying)
1285 setALContext(This->ctx);
1286 /* Perform a flush, so the next timer update will restart at the
1287 * proper position */
1288 alSourceRewind(This->source);
1289 alSourcei(This->source, AL_BUFFER, 0);
1290 checkALError();
1291 popALContext();
1293 This->queue_base = This->data_offset = pos;
1294 This->curidx = 0;
1296 else
1298 setALContext(This->ctx);
1299 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1300 checkALError();
1301 popALContext();
1303 This->lastpos = pos;
1305 LeaveCriticalSection(This->crst);
1306 return DS_OK;
1309 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1311 /* This call only works on primary buffers */
1312 WARN("(%p)->(%p)\n", iface, wfx);
1313 return DSERR_INVALIDCALL;
1316 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1318 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1319 HRESULT hr = S_OK;
1321 TRACE("(%p)->(%ld)\n", iface, vol);
1323 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1325 WARN("Invalid volume (%ld)\n", vol);
1326 return DSERR_INVALIDPARAM;
1329 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1330 hr = DSERR_CONTROLUNAVAIL;
1331 if(SUCCEEDED(hr))
1333 ALfloat fvol = mB_to_gain(vol);
1334 setALContext(This->ctx);
1335 alSourcef(This->source, AL_GAIN, fvol);
1336 popALContext();
1339 return hr;
1342 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1344 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1345 HRESULT hr = S_OK;
1347 TRACE("(%p)->(%ld)\n", iface, pan);
1349 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1351 WARN("invalid parameter: pan = %ld\n", pan);
1352 return DSERR_INVALIDPARAM;
1355 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1356 hr = DSERR_CONTROLUNAVAIL;
1357 else
1359 if(!(This->buffer->dsbflags&DSBCAPS_CTRL3D))
1361 ALfloat pos[3];
1362 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1363 pos[1] = 0.0f;
1364 /* NOTE: Strict movement along the X plane can cause the sound to
1365 * jump between left and right sharply. Using a curved path helps
1366 * smooth it out.
1368 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1370 setALContext(This->ctx);
1371 alSourcefv(This->source, AL_POSITION, pos);
1372 checkALError();
1373 popALContext();
1377 return hr;
1380 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1382 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1383 HRESULT hr = S_OK;
1385 TRACE("(%p)->(%lu)\n", iface, freq);
1387 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1389 WARN("invalid parameter: freq = %lu\n", freq);
1390 return DSERR_INVALIDPARAM;
1393 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1394 hr = DSERR_CONTROLUNAVAIL;
1395 else
1397 ALfloat pitch = 1.0f;
1398 if(freq != DSBFREQUENCY_ORIGINAL)
1399 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1401 setALContext(This->ctx);
1402 alSourcef(This->source, AL_PITCH, pitch);
1403 checkALError();
1404 popALContext();
1407 return hr;
1410 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1412 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1414 TRACE("(%p)->()\n", iface);
1416 EnterCriticalSection(This->crst);
1417 setALContext(This->ctx);
1419 alSourcePause(This->source);
1420 checkALError();
1422 This->isplaying = FALSE;
1423 DS8Primary_triggernots(This->primary);
1425 popALContext();
1426 LeaveCriticalSection(This->crst);
1428 return S_OK;
1431 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1433 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1434 DS8Data *buf = This->buffer;
1435 DWORD bufsize = buf->buf_size;
1436 DWORD_PTR ofs1, ofs2;
1437 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1438 HRESULT hr;
1440 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1442 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1444 WARN("Not locked\n");
1445 return DSERR_INVALIDPARAM;
1448 hr = DSERR_INVALIDPARAM;
1449 /* Make sure offset is between boundary and boundary + bufsize */
1450 ofs1 = (DWORD_PTR)ptr1;
1451 ofs2 = (DWORD_PTR)ptr2;
1452 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1453 goto out;
1454 ofs1 -= boundary;
1455 ofs2 = 0;
1456 if(bufsize-ofs1 < len1 || len2 > ofs1)
1457 goto out;
1458 if(!ptr2)
1459 len2 = 0;
1461 hr = DS_OK;
1462 if(!len1 && !len2)
1463 goto out;
1465 if(BITFIELD_TEST(This->primary->Exts, SOFTX_MAP_BUFFER))
1467 setALContext(This->ctx);
1468 alFlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1469 checkALError();
1470 popALContext();
1472 else if(This->segsize == 0)
1474 setALContext(This->ctx);
1475 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1476 buf->format.Format.nSamplesPerSec);
1477 checkALError();
1478 popALContext();
1481 out:
1482 if(hr != S_OK)
1483 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1484 return hr;
1487 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1489 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1490 HRESULT hr;
1492 TRACE("(%p)->()\n", iface);
1494 EnterCriticalSection(This->crst);
1495 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1496 iface == This->primary->write_emu)
1498 This->bufferlost = 0;
1499 hr = S_OK;
1501 else
1502 hr = DSERR_BUFFERLOST;
1503 LeaveCriticalSection(This->crst);
1505 return hr;
1508 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1510 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1511 ALenum state = AL_INITIAL;
1512 DS8Data *data;
1513 HRESULT hr;
1514 DWORD i;
1516 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1518 data = This->buffer;
1519 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1521 WARN("FX control not set\n");
1522 return DSERR_CONTROLUNAVAIL;
1525 if(data->locked)
1527 WARN("Buffer is locked\n");
1528 return DSERR_INVALIDCALL;
1531 EnterCriticalSection(This->crst);
1532 setALContext(This->ctx);
1534 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1535 checkALError();
1536 if(This->segsize != 0 && state != AL_PLAYING)
1537 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1538 if(state == AL_PLAYING)
1540 WARN("Buffer is playing\n");
1541 hr = DSERR_INVALIDCALL;
1542 goto done;
1545 hr = DSERR_INVALIDPARAM;
1546 if(fxcount == 0)
1548 if(desc || rescodes)
1550 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1551 goto done;
1554 /* No effects; we can handle that */
1555 hr = DS_OK;
1556 goto done;
1559 if(!desc || !rescodes)
1561 WARN("NULL desc and/or result pointer specified.\n");
1562 goto done;
1565 /* We don't (currently) handle DSound effects */
1566 for(i = 0;i < fxcount;++i)
1568 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1569 rescodes[i] = DSFXR_FAILED;
1571 hr = DS_INCOMPLETE;
1573 done:
1574 popALContext();
1575 LeaveCriticalSection(This->crst);
1577 return hr;
1580 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1582 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1584 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1586 /* effects aren't supported at the moment.. */
1587 if(fxcount != 0 || rescodes)
1589 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1590 return DSERR_INVALIDPARAM;
1593 EnterCriticalSection(This->crst);
1594 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1596 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1597 if((flags&DSBPLAY_LOCSOFTWARE))
1598 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1599 else
1600 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1602 LeaveCriticalSection(This->crst);
1604 return S_OK;
1607 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1609 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1610 return E_NOTIMPL;
1613 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1614 DS8Buffer_QueryInterface,
1615 DS8Buffer_AddRef,
1616 DS8Buffer_Release,
1617 DS8Buffer_GetCaps,
1618 DS8Buffer_GetCurrentPosition,
1619 DS8Buffer_GetFormat,
1620 DS8Buffer_GetVolume,
1621 DS8Buffer_GetPan,
1622 DS8Buffer_GetFrequency,
1623 DS8Buffer_GetStatus,
1624 DS8Buffer_Initialize,
1625 DS8Buffer_Lock,
1626 DS8Buffer_Play,
1627 DS8Buffer_SetCurrentPosition,
1628 DS8Buffer_SetFormat,
1629 DS8Buffer_SetVolume,
1630 DS8Buffer_SetPan,
1631 DS8Buffer_SetFrequency,
1632 DS8Buffer_Stop,
1633 DS8Buffer_Unlock,
1634 DS8Buffer_Restore,
1635 DS8Buffer_SetFX,
1636 DS8Buffer_AcquireResources,
1637 DS8Buffer_GetObjectInPath
1641 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, const EAX20BUFFERPROPERTIES *eax_params, LONG flags)
1643 const ALuint source = This->source;
1644 union BufferParamFlags dirty = { flags };
1646 if(dirty.bit.pos)
1647 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1648 -params->vPosition.z);
1649 if(dirty.bit.vel)
1650 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1651 -params->vVelocity.z);
1652 if(dirty.bit.cone_angles)
1654 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1655 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1657 if(dirty.bit.cone_orient)
1658 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1659 params->vConeOrientation.y,
1660 -params->vConeOrientation.z);
1661 if(dirty.bit.cone_outsidevolume)
1662 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1663 if(dirty.bit.min_distance)
1664 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1665 if(dirty.bit.max_distance)
1666 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1667 if(dirty.bit.mode)
1669 This->ds3dmode = params->dwMode;
1670 if(BITFIELD_TEST(This->primary->Exts, SOFT_SOURCE_SPATIALIZE))
1671 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT,
1672 (params->dwMode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
1673 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1674 AL_TRUE : AL_FALSE);
1675 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1676 0.0f : This->primary->rollofffactor);
1679 if(dirty.bit.dry_filter)
1680 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
1681 if(dirty.bit.wet_filter)
1682 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, This->filter[1]);
1683 if(dirty.bit.room_rolloff)
1684 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
1685 if(dirty.bit.cone_outsidevolumehf)
1686 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain(eax_params->lOutsideVolumeHF));
1687 if(dirty.bit.air_absorb)
1688 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, eax_params->flAirAbsorptionFactor);
1689 if(dirty.bit.flags)
1691 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
1692 (eax_params->dwFlags&EAXBUFFERFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
1693 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
1694 (eax_params->dwFlags&EAXBUFFERFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
1695 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
1696 (eax_params->dwFlags&EAXBUFFERFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
1700 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1702 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1703 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1706 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1708 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1709 LONG ret;
1711 InterlockedIncrement(&This->all_ref);
1712 ret = InterlockedIncrement(&This->ds3d_ref);
1713 TRACE("new refcount %ld\n", ret);
1715 return ret;
1718 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1720 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1721 LONG ret;
1723 ret = InterlockedDecrement(&This->ds3d_ref);
1724 TRACE("new refcount %ld\n", ret);
1725 if(InterlockedDecrement(&This->all_ref) == 0)
1726 DS8Buffer_Destroy(This);
1728 return ret;
1731 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1733 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1734 ALint inangle, outangle;
1736 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1737 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1739 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1740 return DSERR_INVALIDPARAM;
1743 EnterCriticalSection(This->crst);
1744 setALContext(This->ctx);
1746 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1747 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1748 checkALError();
1750 popALContext();
1751 LeaveCriticalSection(This->crst);
1753 *pdwInsideConeAngle = inangle;
1754 *pdwOutsideConeAngle = outangle;
1755 return S_OK;
1758 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1760 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1761 ALfloat dir[3];
1763 TRACE("(%p)->(%p)\n", This, orient);
1764 if(!orient)
1766 WARN("Invalid pointer\n");
1767 return DSERR_INVALIDPARAM;
1770 setALContext(This->ctx);
1771 alGetSourcefv(This->source, AL_DIRECTION, dir);
1772 checkALError();
1773 popALContext();
1775 orient->x = dir[0];
1776 orient->y = dir[1];
1777 orient->z = -dir[2];
1778 return S_OK;
1781 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1783 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1784 ALfloat gain;
1786 TRACE("(%p)->(%p)\n", This, vol);
1787 if(!vol)
1789 WARN("Invalid pointer\n");
1790 return DSERR_INVALIDPARAM;
1793 setALContext(This->ctx);
1794 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1795 checkALError();
1796 popALContext();
1798 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1799 return S_OK;
1802 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1804 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1805 ALfloat dist;
1807 TRACE("(%p)->(%p)\n", This, maxdist);
1808 if(!maxdist)
1810 WARN("Invalid pointer\n");
1811 return DSERR_INVALIDPARAM;
1814 setALContext(This->ctx);
1815 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1816 checkALError();
1817 popALContext();
1819 *maxdist = dist;
1820 return S_OK;
1823 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1825 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1826 ALfloat dist;
1828 TRACE("(%p)->(%p)\n", This, mindist);
1829 if(!mindist)
1831 WARN("Invalid pointer\n");
1832 return DSERR_INVALIDPARAM;
1835 setALContext(This->ctx);
1836 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1837 checkALError();
1838 popALContext();
1840 *mindist = dist;
1841 return S_OK;
1844 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1846 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1848 TRACE("(%p)->(%p)\n", This, mode);
1849 if(!mode)
1851 WARN("Invalid pointer\n");
1852 return DSERR_INVALIDPARAM;
1855 EnterCriticalSection(This->crst);
1856 *mode = This->ds3dmode;
1857 LeaveCriticalSection(This->crst);
1859 return S_OK;
1862 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1864 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1865 ALfloat alpos[3];
1867 TRACE("(%p)->(%p)\n", This, pos);
1868 if(!pos)
1870 WARN("Invalid pointer\n");
1871 return DSERR_INVALIDPARAM;
1874 setALContext(This->ctx);
1875 alGetSourcefv(This->source, AL_POSITION, alpos);
1876 checkALError();
1877 popALContext();
1879 pos->x = alpos[0];
1880 pos->y = alpos[1];
1881 pos->z = -alpos[2];
1882 return S_OK;
1885 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1887 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1888 ALfloat alvel[3];
1890 TRACE("(%p)->(%p)\n", This, vel);
1891 if(!vel)
1893 WARN("Invalid pointer\n");
1894 return DSERR_INVALIDPARAM;
1897 setALContext(This->ctx);
1898 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1899 checkALError();
1900 popALContext();
1902 vel->x = alvel[0];
1903 vel->y = alvel[1];
1904 vel->z = -alvel[2];
1905 return S_OK;
1908 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1910 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1912 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1914 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1916 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1917 return DSERR_INVALIDPARAM;
1920 EnterCriticalSection(This->crst);
1921 setALContext(This->ctx);
1923 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1924 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1925 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1926 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1927 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1928 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1929 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
1930 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
1932 popALContext();
1933 LeaveCriticalSection(This->crst);
1935 return DS_OK;
1938 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
1940 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1942 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
1943 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
1944 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
1946 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
1947 return DSERR_INVALIDPARAM;
1950 EnterCriticalSection(This->crst);
1951 if(apply == DS3D_DEFERRED)
1953 This->params.dwInsideConeAngle = dwInsideConeAngle;
1954 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
1955 This->dirty.bit.cone_angles = 1;
1957 else
1959 setALContext(This->ctx);
1960 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
1961 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
1962 checkALError();
1963 popALContext();
1965 LeaveCriticalSection(This->crst);
1967 return S_OK;
1970 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1972 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1974 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
1976 if(apply == DS3D_DEFERRED)
1978 EnterCriticalSection(This->crst);
1979 This->params.vConeOrientation.x = x;
1980 This->params.vConeOrientation.y = y;
1981 This->params.vConeOrientation.z = z;
1982 This->dirty.bit.cone_orient = 1;
1983 LeaveCriticalSection(This->crst);
1985 else
1987 setALContext(This->ctx);
1988 alSource3f(This->source, AL_DIRECTION, x, y, -z);
1989 checkALError();
1990 popALContext();
1993 return S_OK;
1996 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
1998 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2000 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2001 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2003 WARN("Invalid volume (%ld)\n", vol);
2004 return DSERR_INVALIDPARAM;
2007 if(apply == DS3D_DEFERRED)
2009 EnterCriticalSection(This->crst);
2010 This->params.lConeOutsideVolume = vol;
2011 This->dirty.bit.cone_outsidevolume = 1;
2012 LeaveCriticalSection(This->crst);
2014 else
2016 setALContext(This->ctx);
2017 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2018 checkALError();
2019 popALContext();
2022 return S_OK;
2025 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2027 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2029 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2030 if(maxdist < 0.0f)
2032 WARN("Invalid max distance (%f)\n", maxdist);
2033 return DSERR_INVALIDPARAM;
2036 if(apply == DS3D_DEFERRED)
2038 EnterCriticalSection(This->crst);
2039 This->params.flMaxDistance = maxdist;
2040 This->dirty.bit.max_distance = 1;
2041 LeaveCriticalSection(This->crst);
2043 else
2045 setALContext(This->ctx);
2046 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2047 checkALError();
2048 popALContext();
2051 return S_OK;
2054 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2056 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2058 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2059 if(mindist < 0.0f)
2061 WARN("Invalid min distance (%f)\n", mindist);
2062 return DSERR_INVALIDPARAM;
2065 if(apply == DS3D_DEFERRED)
2067 EnterCriticalSection(This->crst);
2068 This->params.flMinDistance = mindist;
2069 This->dirty.bit.min_distance = 1;
2070 LeaveCriticalSection(This->crst);
2072 else
2074 setALContext(This->ctx);
2075 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2076 checkALError();
2077 popALContext();
2080 return S_OK;
2083 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2085 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2087 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2088 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2089 mode != DS3DMODE_DISABLE)
2091 WARN("Invalid mode (%lu)\n", mode);
2092 return DSERR_INVALIDPARAM;
2095 EnterCriticalSection(This->crst);
2096 if(apply == DS3D_DEFERRED)
2098 This->params.dwMode = mode;
2099 This->dirty.bit.mode = 1;
2101 else
2103 setALContext(This->ctx);
2104 This->ds3dmode = mode;
2105 if(BITFIELD_TEST(This->primary->Exts, SOFT_SOURCE_SPATIALIZE))
2106 alSourcei(This->source, AL_SOURCE_SPATIALIZE_SOFT,
2107 (mode==DS3DMODE_DISABLE) ? AL_FALSE : AL_TRUE);
2108 alSourcei(This->source, AL_SOURCE_RELATIVE,
2109 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2110 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2111 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2112 checkALError();
2113 popALContext();
2115 LeaveCriticalSection(This->crst);
2117 return S_OK;
2120 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2122 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2124 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2126 if(apply == DS3D_DEFERRED)
2128 EnterCriticalSection(This->crst);
2129 This->params.vPosition.x = x;
2130 This->params.vPosition.y = y;
2131 This->params.vPosition.z = z;
2132 This->dirty.bit.pos = 1;
2133 LeaveCriticalSection(This->crst);
2135 else
2137 setALContext(This->ctx);
2138 alSource3f(This->source, AL_POSITION, x, y, -z);
2139 checkALError();
2140 popALContext();
2143 return S_OK;
2146 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2148 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2150 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2152 if(apply == DS3D_DEFERRED)
2154 EnterCriticalSection(This->crst);
2155 This->params.vVelocity.x = x;
2156 This->params.vVelocity.y = y;
2157 This->params.vVelocity.z = z;
2158 This->dirty.bit.vel = 1;
2159 LeaveCriticalSection(This->crst);
2161 else
2163 setALContext(This->ctx);
2164 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2165 checkALError();
2166 popALContext();
2169 return S_OK;
2172 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2174 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2175 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2177 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2179 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2180 return DSERR_INVALIDPARAM;
2183 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2184 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2186 WARN("Invalid cone angles (%lu, %lu)\n",
2187 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2188 return DSERR_INVALIDPARAM;
2191 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2192 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2194 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2195 return DSERR_INVALIDPARAM;
2198 if(ds3dbuffer->flMaxDistance < 0.0f)
2200 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2201 return DSERR_INVALIDPARAM;
2204 if(ds3dbuffer->flMinDistance < 0.0f)
2206 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2207 return DSERR_INVALIDPARAM;
2210 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2211 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2212 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2214 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2215 return DSERR_INVALIDPARAM;
2218 if(apply == DS3D_DEFERRED)
2220 EnterCriticalSection(This->crst);
2221 This->params = *ds3dbuffer;
2222 This->params.dwSize = sizeof(This->params);
2223 This->dirty.bit.pos = 1;
2224 This->dirty.bit.vel = 1;
2225 This->dirty.bit.cone_angles = 1;
2226 This->dirty.bit.cone_orient = 1;
2227 This->dirty.bit.cone_outsidevolume = 1;
2228 This->dirty.bit.min_distance = 1;
2229 This->dirty.bit.max_distance = 1;
2230 This->dirty.bit.mode = 1;
2231 LeaveCriticalSection(This->crst);
2233 else
2235 union BufferParamFlags dirty = { 0 };
2236 dirty.bit.pos = 1;
2237 dirty.bit.vel = 1;
2238 dirty.bit.cone_angles = 1;
2239 dirty.bit.cone_orient = 1;
2240 dirty.bit.cone_outsidevolume = 1;
2241 dirty.bit.min_distance = 1;
2242 dirty.bit.max_distance = 1;
2243 dirty.bit.mode = 1;
2245 EnterCriticalSection(This->crst);
2246 setALContext(This->ctx);
2247 DS8Buffer_SetParams(This, ds3dbuffer, NULL, dirty.flags);
2248 checkALError();
2249 popALContext();
2250 LeaveCriticalSection(This->crst);
2253 return S_OK;
2256 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2258 DS8Buffer3D_QueryInterface,
2259 DS8Buffer3D_AddRef,
2260 DS8Buffer3D_Release,
2261 DS8Buffer3D_GetAllParameters,
2262 DS8Buffer3D_GetConeAngles,
2263 DS8Buffer3D_GetConeOrientation,
2264 DS8Buffer3D_GetConeOutsideVolume,
2265 DS8Buffer3D_GetMaxDistance,
2266 DS8Buffer3D_GetMinDistance,
2267 DS8Buffer3D_GetMode,
2268 DS8Buffer3D_GetPosition,
2269 DS8Buffer3D_GetVelocity,
2270 DS8Buffer3D_SetAllParameters,
2271 DS8Buffer3D_SetConeAngles,
2272 DS8Buffer3D_SetConeOrientation,
2273 DS8Buffer3D_SetConeOutsideVolume,
2274 DS8Buffer3D_SetMaxDistance,
2275 DS8Buffer3D_SetMinDistance,
2276 DS8Buffer3D_SetMode,
2277 DS8Buffer3D_SetPosition,
2278 DS8Buffer3D_SetVelocity
2282 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2284 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2285 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2288 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2290 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2291 LONG ret;
2293 InterlockedIncrement(&This->all_ref);
2294 ret = InterlockedIncrement(&This->not_ref);
2295 TRACE("new refcount %ld\n", ret);
2297 return ret;
2300 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2302 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2303 LONG ret;
2305 ret = InterlockedDecrement(&This->not_ref);
2306 TRACE("new refcount %ld\n", ret);
2307 if(InterlockedDecrement(&This->all_ref) == 0)
2308 DS8Buffer_Destroy(This);
2310 return ret;
2313 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2315 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2316 DSBPOSITIONNOTIFY *nots;
2317 DWORD state;
2318 HRESULT hr;
2320 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2322 EnterCriticalSection(This->crst);
2323 hr = DSERR_INVALIDPARAM;
2324 if(count && !notifications)
2325 goto out;
2327 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2328 if(FAILED(hr)) goto out;
2330 hr = DSERR_INVALIDCALL;
2331 if((state&DSBSTATUS_PLAYING))
2332 goto out;
2334 if(!count)
2336 HeapFree(GetProcessHeap(), 0, This->notify);
2337 This->notify = 0;
2338 This->nnotify = 0;
2339 hr = S_OK;
2341 else
2343 DWORD i;
2345 hr = DSERR_INVALIDPARAM;
2346 for(i = 0;i < count;++i)
2348 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2349 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2350 goto out;
2353 hr = E_OUTOFMEMORY;
2354 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2355 if(!nots) goto out;
2356 memcpy(nots, notifications, count*sizeof(*nots));
2358 HeapFree(GetProcessHeap(), 0, This->notify);
2359 This->notify = nots;
2360 This->nnotify = count;
2362 hr = S_OK;
2365 out:
2366 LeaveCriticalSection(This->crst);
2367 return hr;
2370 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2372 DS8BufferNot_QueryInterface,
2373 DS8BufferNot_AddRef,
2374 DS8BufferNot_Release,
2375 DS8BufferNot_SetNotificationPositions
2379 static void ApplyReverbParams(DS8Primary *prim, const EAXLISTENERPROPERTIES *props)
2381 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
2382 prim->eax_prop = *props;
2383 alEffectf(prim->effect, AL_REVERB_DENSITY,
2384 clampF(powf(props->flEnvironmentSize, 3.0f) / 16.0f, 0.0f, 1.0f)
2386 alEffectf(prim->effect, AL_REVERB_DIFFUSION, props->flEnvironmentDiffusion);
2388 alEffectf(prim->effect, AL_REVERB_GAIN, mB_to_gain(props->lRoom));
2389 alEffectf(prim->effect, AL_REVERB_GAINHF, mB_to_gain(props->lRoomHF));
2391 alEffectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
2393 alEffectf(prim->effect, AL_REVERB_DECAY_TIME, props->flDecayTime);
2394 alEffectf(prim->effect, AL_REVERB_DECAY_HFRATIO, props->flDecayHFRatio);
2396 alEffectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN, mB_to_gain(props->lReflections));
2397 alEffectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
2399 alEffectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN, mB_to_gain(props->lReverb));
2400 alEffectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY, props->flReverbDelay);
2402 alEffectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2403 mB_to_gain(props->flAirAbsorptionHF));
2405 alEffecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2406 (props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2407 AL_TRUE : AL_FALSE);
2409 checkALError();
2411 prim->dirty.bit.effect = 1;
2414 #define APPLY_DRY_PARAMS 1
2415 #define APPLY_WET_PARAMS 2
2416 static void ApplyFilterParams(DS8Buffer *buf, const EAX20BUFFERPROPERTIES *props, int apply)
2418 /* The LFRatio properties determine how much the given level applies to low
2419 * frequencies as well as high frequencies. Given that the high frequency
2420 * levels are specified relative to the low, they should increase as the
2421 * low frequency levels reduce.
2423 FLOAT occl = props->lOcclusion * props->flOcclusionLFRatio;
2424 FLOAT occlhf = props->lOcclusion * (1.0f-props->flOcclusionLFRatio);
2426 if((apply&APPLY_DRY_PARAMS))
2428 FLOAT obstr = props->lObstruction * props->flObstructionLFRatio;
2429 FLOAT obstrhf = props->lObstruction * (1.0f-props->flObstructionLFRatio);
2430 FLOAT mb = props->lDirect + obstr + occl;
2431 FLOAT mbhf = props->lDirectHF + obstrhf + occlhf;
2433 alFilterf(buf->filter[0], AL_LOWPASS_GAIN, mB_to_gain(mb));
2434 alFilterf(buf->filter[0], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
2436 if((apply&APPLY_WET_PARAMS))
2438 FLOAT occlroom = props->flOcclusionRoomRatio;
2439 FLOAT mb = props->lRoom + occlroom*occl;
2440 FLOAT mbhf = props->lRoomHF + occlroom*occlhf;
2442 alFilterf(buf->filter[1], AL_LOWPASS_GAIN, mB_to_gain(mb));
2443 alFilterf(buf->filter[1], AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
2445 checkALError();
2448 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2450 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2451 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2454 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2456 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2457 LONG ret;
2459 InterlockedIncrement(&This->all_ref);
2460 ret = InterlockedIncrement(&This->prop_ref);
2461 TRACE("new refcount %ld\n", ret);
2463 return ret;
2466 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2468 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2469 LONG ret;
2471 ret = InterlockedDecrement(&This->prop_ref);
2472 TRACE("new refcount %ld\n", ret);
2473 if(InterlockedDecrement(&This->all_ref) == 0)
2474 DS8Buffer_Destroy(This);
2476 return ret;
2479 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2480 handled through secondary buffers. */
2481 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2482 REFGUID guidPropSet, ULONG dwPropID,
2483 LPVOID pInstanceData, ULONG cbInstanceData,
2484 LPVOID pPropData, ULONG cbPropData,
2485 ULONG *pcbReturned)
2487 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2488 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2490 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2491 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2493 if(!pcbReturned)
2494 return E_POINTER;
2495 *pcbReturned = 0;
2497 if(cbPropData > 0 && !pPropData)
2499 WARN("pPropData is NULL with cbPropData > 0\n");
2500 return E_POINTER;
2503 #define GET_PROP(hr, retsize, dst, dstsize, src, Type) do { \
2504 if(cbPropData >= sizeof(Type)) \
2506 union { \
2507 void *v; \
2508 Type *props; \
2509 } data = { dst }; \
2511 *data.props = src; \
2512 *(retsize) = sizeof(Type); \
2513 *(hr) = DS_OK; \
2515 } while(0)
2516 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2518 EnterCriticalSection(This->crst);
2520 hr = DSERR_INVALIDPARAM;
2521 if(This->filter[0] == 0)
2522 hr = E_PROP_ID_UNSUPPORTED;
2523 else switch(dwPropID)
2525 case DSPROPERTY_EAXBUFFER_ALLPARAMETERS:
2526 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop,
2527 EAX20BUFFERPROPERTIES);
2528 break;
2530 case DSPROPERTY_EAXBUFFER_DIRECT:
2531 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lDirect,
2532 LONG);
2533 break;
2534 case DSPROPERTY_EAXBUFFER_DIRECTHF:
2535 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lDirectHF,
2536 LONG);
2537 break;
2539 case DSPROPERTY_EAXBUFFER_ROOM:
2540 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lRoom,
2541 LONG);
2542 break;
2543 case DSPROPERTY_EAXBUFFER_ROOMHF:
2544 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lRoomHF,
2545 LONG);
2546 break;
2548 case DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR:
2549 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flRoomRolloffFactor,
2550 FLOAT);
2551 break;
2553 case DSPROPERTY_EAXBUFFER_OBSTRUCTION:
2554 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lObstruction,
2555 LONG);
2556 break;
2557 case DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO:
2558 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flObstructionLFRatio,
2559 FLOAT);
2560 break;
2562 case DSPROPERTY_EAXBUFFER_OCCLUSION:
2563 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lOcclusion,
2564 LONG);
2565 break;
2566 case DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO:
2567 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flOcclusionLFRatio,
2568 FLOAT);
2569 break;
2570 case DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO:
2571 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flOcclusionRoomRatio,
2572 FLOAT);
2573 break;
2575 case DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF:
2576 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lOutsideVolumeHF,
2577 LONG);
2578 break;
2580 case DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR:
2581 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flAirAbsorptionFactor,
2582 FLOAT);
2583 break;
2585 case DSPROPERTY_EAXBUFFER_FLAGS:
2586 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.dwFlags,
2587 DWORD);
2588 break;
2590 default:
2591 hr = E_PROP_ID_UNSUPPORTED;
2592 FIXME("Unhandled buffer propid: 0x%08lx\n", dwPropID);
2593 break;
2596 LeaveCriticalSection(This->crst);
2598 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2600 DS8Primary *prim = This->primary;
2602 EnterCriticalSection(This->crst);
2604 hr = DSERR_INVALIDPARAM;
2605 if(prim->effect == 0)
2606 hr = E_PROP_ID_UNSUPPORTED;
2607 else switch(dwPropID)
2609 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2610 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, prim->eax_prop,
2611 EAXLISTENERPROPERTIES);
2612 break;
2614 case DSPROPERTY_EAXLISTENER_ROOM:
2615 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2616 prim->eax_prop.lRoom, LONG);
2617 break;
2618 case DSPROPERTY_EAXLISTENER_ROOMHF:
2619 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2620 prim->eax_prop.lRoomHF, LONG);
2621 break;
2623 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2624 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2625 prim->eax_prop.flRoomRolloffFactor, FLOAT);
2626 break;
2628 case DSPROPERTY_EAXLISTENER_DECAYTIME:
2629 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2630 prim->eax_prop.flDecayTime, FLOAT);
2631 break;
2632 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
2633 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2634 prim->eax_prop.flDecayHFRatio, FLOAT);
2635 break;
2637 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
2638 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2639 prim->eax_prop.lReflections, LONG);
2640 break;
2641 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
2642 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2643 prim->eax_prop.flReflectionsDelay, FLOAT);
2644 break;
2646 case DSPROPERTY_EAXLISTENER_REVERB:
2647 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2648 prim->eax_prop.lReverb, LONG);
2649 break;
2650 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
2651 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2652 prim->eax_prop.flReverbDelay, FLOAT);
2653 break;
2655 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2656 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2657 prim->eax_prop.dwEnvironment, DWORD);
2658 break;
2660 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2661 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2662 prim->eax_prop.flEnvironmentSize, FLOAT);
2663 break;
2664 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2665 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2666 prim->eax_prop.flEnvironmentDiffusion, FLOAT);
2667 break;
2669 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2670 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2671 prim->eax_prop.flAirAbsorptionHF, FLOAT);
2672 break;
2674 case DSPROPERTY_EAXLISTENER_FLAGS:
2675 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2676 prim->eax_prop.dwFlags, DWORD);
2677 break;
2679 default:
2680 hr = E_PROP_ID_UNSUPPORTED;
2681 FIXME("Unhandled listener propid: 0x%08lx\n", dwPropID);
2682 break;
2685 LeaveCriticalSection(This->crst);
2687 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX_ReverbProperties))
2689 DS8Primary *prim = This->primary;
2691 EnterCriticalSection(This->crst);
2693 hr = DSERR_INVALIDPARAM;
2694 if(prim->effect == 0)
2695 hr = E_PROP_ID_UNSUPPORTED;
2696 else switch(dwPropID)
2698 case DSPROPERTY_EAX1_ALL:
2699 if(cbPropData >= sizeof(EAX1_REVERBPROPERTIES))
2701 union {
2702 void *v;
2703 EAX1_REVERBPROPERTIES *props;
2704 } data = { pPropData };
2706 data.props->dwEnvironment = prim->eax_prop.dwEnvironment;
2707 data.props->fVolume = mB_to_gain(prim->eax_prop.lRoom);
2708 data.props->fDecayTime = prim->eax_prop.flDecayTime;
2709 data.props->fDamping = prim->eax1_dampening;
2711 *pcbReturned = sizeof(EAX1_REVERBPROPERTIES);
2712 hr = DS_OK;
2714 break;
2716 case DSPROPERTY_EAX1_ENVIRONMENT:
2717 if(cbPropData >= sizeof(DWORD))
2719 union {
2720 void *v;
2721 DWORD *props;
2722 } data = { pPropData };
2724 *data.props = prim->eax_prop.dwEnvironment;
2726 *pcbReturned = sizeof(DWORD);
2727 hr = DS_OK;
2729 break;
2731 case DSPROPERTY_EAX1_VOLUME:
2732 if(cbPropData >= sizeof(float))
2734 union {
2735 void *v;
2736 float *props;
2737 } data = { pPropData };
2739 *data.props = mB_to_gain(prim->eax_prop.lRoom);
2741 *pcbReturned = sizeof(float);
2742 hr = DS_OK;
2744 break;
2746 case DSPROPERTY_EAX1_DECAYTIME:
2747 if(cbPropData >= sizeof(float))
2749 union {
2750 void *v;
2751 float *props;
2752 } data = { pPropData };
2754 *data.props = prim->eax_prop.flDecayTime;
2756 *pcbReturned = sizeof(float);
2757 hr = DS_OK;
2759 break;
2761 case DSPROPERTY_EAX1_DAMPING:
2762 if(cbPropData >= sizeof(float))
2764 union {
2765 void *v;
2766 float *props;
2767 } data = { pPropData };
2769 *data.props = prim->eax1_dampening;
2771 *pcbReturned = sizeof(float);
2772 hr = DS_OK;
2774 break;
2776 default:
2777 hr = E_PROP_ID_UNSUPPORTED;
2778 FIXME("Unhandled EAX1 listener propid: 0x%08lx\n", dwPropID);
2779 break;
2782 LeaveCriticalSection(This->crst);
2784 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAXBUFFER_ReverbProperties))
2786 EnterCriticalSection(This->crst);
2788 hr = DSERR_INVALIDPARAM;
2789 if(This->filter[0] == 0)
2790 hr = E_PROP_ID_UNSUPPORTED;
2791 else switch(dwPropID)
2793 /* NOTE: DSPROPERTY_EAX1BUFFER_ALL is for EAX1BUFFER_REVERBPROPERTIES,
2794 * however that struct just contains the single ReverbMix float
2795 * property.
2797 case DSPROPERTY_EAX1BUFFER_ALL:
2798 case DSPROPERTY_EAX1BUFFER_REVERBMIX:
2799 if(cbPropData >= sizeof(float))
2801 union {
2802 void *v;
2803 float *props;
2804 } data = { pPropData };
2806 *data.props = mB_to_gain(This->eax_prop.lRoom);
2807 *pcbReturned = sizeof(float);
2808 hr = DS_OK;
2810 break;
2812 default:
2813 hr = E_PROP_ID_UNSUPPORTED;
2814 FIXME("Unhandled EAX1 buffer propid: 0x%08lx\n", dwPropID);
2815 break;
2818 LeaveCriticalSection(This->crst);
2820 else
2821 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2822 #undef GET_PROP
2824 return hr;
2827 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2828 REFGUID guidPropSet, ULONG dwPropID,
2829 LPVOID pInstanceData, ULONG cbInstanceData,
2830 LPVOID pPropData, ULONG cbPropData)
2832 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2833 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2835 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2836 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2838 if(cbPropData > 0 && !pPropData)
2840 WARN("pPropData is NULL with cbPropData > 0\n");
2841 return E_POINTER;
2844 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2846 DWORD propid = dwPropID & ~DSPROPERTY_EAXBUFFER_DEFERRED;
2847 BOOL immediate = !(dwPropID&DSPROPERTY_EAXBUFFER_DEFERRED);
2849 EnterCriticalSection(This->crst);
2850 setALContext(This->ctx);
2852 hr = DSERR_INVALIDPARAM;
2853 if(This->filter[0] == 0)
2854 hr = E_PROP_ID_UNSUPPORTED;
2855 else switch(propid)
2857 case DSPROPERTY_EAXBUFFER_NONE: /* not setting any property, just applying */
2858 hr = DS_OK;
2859 break;
2861 case DSPROPERTY_EAXBUFFER_ALLPARAMETERS:
2862 if(cbPropData >= sizeof(EAX20BUFFERPROPERTIES))
2864 union {
2865 const void *v;
2866 const EAX20BUFFERPROPERTIES *props;
2867 } data = { pPropData };
2869 This->eax_prop = *data.props;
2870 ApplyFilterParams(This, data.props, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
2872 This->dirty.bit.dry_filter = 1;
2873 This->dirty.bit.wet_filter = 1;
2874 This->dirty.bit.room_rolloff = 1;
2875 This->dirty.bit.cone_outsidevolumehf = 1;
2876 This->dirty.bit.air_absorb = 1;
2877 This->dirty.bit.flags = 1;
2878 hr = DS_OK;
2880 break;
2882 case DSPROPERTY_EAXBUFFER_DIRECT:
2883 if(cbPropData >= sizeof(LONG))
2885 union {
2886 const void *v;
2887 const LONG *props;
2888 } data = { pPropData };
2890 This->eax_prop.lDirect = *data.props;
2891 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS);
2893 This->dirty.bit.dry_filter = 1;
2894 hr = DS_OK;
2896 break;
2897 case DSPROPERTY_EAXBUFFER_DIRECTHF:
2898 if(cbPropData >= sizeof(LONG))
2900 union {
2901 const void *v;
2902 const LONG *props;
2903 } data = { pPropData };
2905 This->eax_prop.lDirectHF = *data.props;
2906 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS);
2908 This->dirty.bit.dry_filter = 1;
2909 hr = DS_OK;
2911 break;
2913 case DSPROPERTY_EAXBUFFER_ROOM:
2914 if(cbPropData >= sizeof(LONG))
2916 union {
2917 const void *v;
2918 const LONG *props;
2919 } data = { pPropData };
2921 This->eax_prop.lRoom = *data.props;
2922 ApplyFilterParams(This, &This->eax_prop, APPLY_WET_PARAMS);
2924 This->dirty.bit.wet_filter = 1;
2925 hr = DS_OK;
2927 break;
2928 case DSPROPERTY_EAXBUFFER_ROOMHF:
2929 if(cbPropData >= sizeof(LONG))
2931 union {
2932 const void *v;
2933 const LONG *props;
2934 } data = { pPropData };
2936 This->eax_prop.lRoomHF = *data.props;
2937 ApplyFilterParams(This, &This->eax_prop, APPLY_WET_PARAMS);
2939 This->dirty.bit.wet_filter = 1;
2940 hr = DS_OK;
2942 break;
2944 case DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR:
2945 if(cbPropData >= sizeof(FLOAT))
2947 union {
2948 const void *v;
2949 const FLOAT *props;
2950 } data = { pPropData };
2952 This->eax_prop.flRoomRolloffFactor = *data.props;
2954 This->dirty.bit.room_rolloff = 1;
2955 hr = DS_OK;
2957 break;
2959 case DSPROPERTY_EAXBUFFER_OBSTRUCTION:
2960 if(cbPropData >= sizeof(LONG))
2962 union {
2963 const void *v;
2964 const LONG *props;
2965 } data = { pPropData };
2967 This->eax_prop.lObstruction = *data.props;
2968 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS);
2970 This->dirty.bit.dry_filter = 1;
2971 hr = DS_OK;
2973 break;
2974 case DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO:
2975 if(cbPropData >= sizeof(FLOAT))
2977 union {
2978 const void *v;
2979 const FLOAT *props;
2980 } data = { pPropData };
2982 This->eax_prop.flObstructionLFRatio = *data.props;
2983 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS);
2985 This->dirty.bit.dry_filter = 1;
2986 hr = DS_OK;
2988 break;
2990 case DSPROPERTY_EAXBUFFER_OCCLUSION:
2991 if(cbPropData >= sizeof(LONG))
2993 union {
2994 const void *v;
2995 const LONG *props;
2996 } data = { pPropData };
2998 This->eax_prop.lOcclusion = *data.props;
2999 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
3001 This->dirty.bit.dry_filter = 1;
3002 This->dirty.bit.wet_filter = 1;
3003 hr = DS_OK;
3005 break;
3006 case DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO:
3007 if(cbPropData >= sizeof(FLOAT))
3009 union {
3010 const void *v;
3011 const FLOAT *props;
3012 } data = { pPropData };
3014 This->eax_prop.flOcclusionLFRatio = *data.props;
3015 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
3017 This->dirty.bit.dry_filter = 1;
3018 This->dirty.bit.wet_filter = 1;
3019 hr = DS_OK;
3021 break;
3022 case DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO:
3023 if(cbPropData >= sizeof(FLOAT))
3025 union {
3026 const void *v;
3027 const FLOAT *props;
3028 } data = { pPropData };
3030 This->eax_prop.flOcclusionRoomRatio = *data.props;
3031 ApplyFilterParams(This, &This->eax_prop, APPLY_DRY_PARAMS|APPLY_WET_PARAMS);
3033 This->dirty.bit.dry_filter = 1;
3034 This->dirty.bit.wet_filter = 1;
3035 hr = DS_OK;
3037 break;
3039 case DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF:
3040 if(cbPropData >= sizeof(LONG))
3042 union {
3043 const void *v;
3044 const LONG *props;
3045 } data = { pPropData };
3047 This->eax_prop.lOutsideVolumeHF = *data.props;
3049 This->dirty.bit.cone_outsidevolumehf = 1;
3050 hr = DS_OK;
3052 break;
3054 case DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR:
3055 if(cbPropData >= sizeof(FLOAT))
3057 union {
3058 const void *v;
3059 const FLOAT *props;
3060 } data = { pPropData };
3062 This->eax_prop.flAirAbsorptionFactor = *data.props;
3064 This->dirty.bit.air_absorb = 1;
3065 hr = DS_OK;
3067 break;
3069 case DSPROPERTY_EAXBUFFER_FLAGS:
3070 if(cbPropData >= sizeof(DWORD))
3072 union {
3073 const void *v;
3074 const DWORD *props;
3075 } data = { pPropData };
3077 This->eax_prop.dwFlags = *data.props;
3079 This->dirty.bit.flags = 1;
3080 hr = DS_OK;
3082 break;
3084 default:
3085 hr = E_PROP_ID_UNSUPPORTED;
3086 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
3087 break;
3090 if(hr == DS_OK && immediate)
3091 DS8Primary3D_CommitDeferredSettings(&This->primary->IDirectSound3DListener_iface);
3093 popALContext();
3094 LeaveCriticalSection(This->crst);
3096 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
3098 DS8Primary *prim = This->primary;
3099 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
3100 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
3102 EnterCriticalSection(prim->crst);
3103 setALContext(prim->ctx);
3105 hr = DSERR_INVALIDPARAM;
3106 if(prim->effect == 0)
3107 hr = E_PROP_ID_UNSUPPORTED;
3108 else switch(propid)
3110 case DSPROPERTY_EAXLISTENER_NONE: /* not setting any property, just applying */
3111 hr = DS_OK;
3112 break;
3114 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
3115 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
3117 union {
3118 const void *v;
3119 const EAXLISTENERPROPERTIES *props;
3120 } data = { pPropData };
3122 ApplyReverbParams(prim, data.props);
3123 hr = DS_OK;
3125 break;
3127 case DSPROPERTY_EAXLISTENER_ROOM:
3128 if(cbPropData >= sizeof(LONG))
3130 union {
3131 const void *v;
3132 const LONG *l;
3133 } data = { pPropData };
3135 prim->eax_prop.lRoom = *data.l;
3136 alEffectf(prim->effect, AL_REVERB_GAIN,
3137 mB_to_gain(prim->eax_prop.lRoom));
3138 checkALError();
3140 prim->dirty.bit.effect = 1;
3141 hr = DS_OK;
3143 break;
3144 case DSPROPERTY_EAXLISTENER_ROOMHF:
3145 if(cbPropData >= sizeof(LONG))
3147 union {
3148 const void *v;
3149 const LONG *l;
3150 } data = { pPropData };
3152 prim->eax_prop.lRoomHF = *data.l;
3153 alEffectf(prim->effect, AL_REVERB_GAINHF,
3154 mB_to_gain(prim->eax_prop.lRoomHF));
3155 checkALError();
3157 prim->dirty.bit.effect = 1;
3158 hr = DS_OK;
3160 break;
3162 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
3163 if(cbPropData >= sizeof(FLOAT))
3165 union {
3166 const void *v;
3167 const FLOAT *fl;
3168 } data = { pPropData };
3170 prim->eax_prop.flRoomRolloffFactor = *data.fl;
3171 alEffectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
3172 prim->eax_prop.flRoomRolloffFactor);
3173 checkALError();
3175 prim->dirty.bit.effect = 1;
3176 hr = DS_OK;
3178 break;
3180 case DSPROPERTY_EAXLISTENER_DECAYTIME:
3181 if(cbPropData >= sizeof(FLOAT))
3183 union {
3184 const void *v;
3185 const FLOAT *fl;
3186 } data = { pPropData };
3188 prim->eax_prop.flDecayTime = *data.fl;
3189 alEffectf(prim->effect, AL_REVERB_DECAY_TIME,
3190 prim->eax_prop.flDecayTime);
3191 checkALError();
3193 prim->dirty.bit.effect = 1;
3194 hr = DS_OK;
3196 break;
3197 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
3198 if(cbPropData >= sizeof(FLOAT))
3200 union {
3201 const void *v;
3202 const FLOAT *fl;
3203 } data = { pPropData };
3205 prim->eax_prop.flDecayHFRatio = *data.fl;
3206 alEffectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
3207 prim->eax_prop.flDecayHFRatio);
3208 checkALError();
3210 prim->dirty.bit.effect = 1;
3211 hr = DS_OK;
3213 break;
3215 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
3216 if(cbPropData >= sizeof(LONG))
3218 union {
3219 const void *v;
3220 const LONG *l;
3221 } data = { pPropData };
3223 prim->eax_prop.lReflections = *data.l;
3224 alEffectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
3225 mB_to_gain(prim->eax_prop.lReflections));
3226 checkALError();
3228 prim->dirty.bit.effect = 1;
3229 hr = DS_OK;
3231 break;
3232 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
3233 if(cbPropData >= sizeof(FLOAT))
3235 union {
3236 const void *v;
3237 const FLOAT *fl;
3238 } data = { pPropData };
3240 prim->eax_prop.flReflectionsDelay = *data.fl;
3241 alEffectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
3242 prim->eax_prop.flReflectionsDelay);
3243 checkALError();
3245 prim->dirty.bit.effect = 1;
3246 hr = DS_OK;
3248 break;
3250 case DSPROPERTY_EAXLISTENER_REVERB:
3251 if(cbPropData >= sizeof(LONG))
3253 union {
3254 const void *v;
3255 const LONG *l;
3256 } data = { pPropData };
3258 prim->eax_prop.lReverb = *data.l;
3259 alEffectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
3260 mB_to_gain(prim->eax_prop.lReverb));
3261 checkALError();
3263 prim->dirty.bit.effect = 1;
3264 hr = DS_OK;
3266 break;
3267 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
3268 if(cbPropData >= sizeof(FLOAT))
3270 union {
3271 const void *v;
3272 const FLOAT *fl;
3273 } data = { pPropData };
3275 prim->eax_prop.flReverbDelay = *data.fl;
3276 alEffectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
3277 prim->eax_prop.flReverbDelay);
3278 checkALError();
3280 prim->dirty.bit.effect = 1;
3281 hr = DS_OK;
3283 break;
3285 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
3286 if(cbPropData >= sizeof(DWORD))
3288 union {
3289 const void *v;
3290 const DWORD *dw;
3291 } data = { pPropData };
3293 if(*data.dw <= EAX_MAX_ENVIRONMENT)
3295 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
3296 hr = DS_OK;
3299 break;
3301 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
3302 if(cbPropData >= sizeof(FLOAT))
3304 union {
3305 const void *v;
3306 const FLOAT *fl;
3307 } data = { pPropData };
3309 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
3311 float scale = (*data.fl)/prim->eax_prop.flEnvironmentSize;
3313 prim->eax_prop.flEnvironmentSize = *data.fl;
3315 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
3317 prim->eax_prop.flDecayTime *= scale;
3318 prim->eax_prop.flDecayTime = clampF(prim->eax_prop.flDecayTime, 0.1f, 20.0f);
3320 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
3322 prim->eax_prop.lReflections -= gain_to_mB(scale);
3323 prim->eax_prop.lReflections = clampI(prim->eax_prop.lReflections, -10000, 1000);
3325 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
3327 prim->eax_prop.flReflectionsDelay *= scale;
3328 prim->eax_prop.flReflectionsDelay = clampF(prim->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
3330 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
3332 prim->eax_prop.lReverb -= gain_to_mB(scale);
3333 prim->eax_prop.lReverb = clampI(prim->eax_prop.lReverb, -10000, 2000);
3335 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
3337 prim->eax_prop.flReverbDelay *= scale;
3338 prim->eax_prop.flReverbDelay = clampF(prim->eax_prop.flReverbDelay, 0.0f, 0.1f);
3341 ApplyReverbParams(prim, &prim->eax_prop);
3342 hr = DS_OK;
3345 break;
3346 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
3347 if(cbPropData >= sizeof(FLOAT))
3349 union {
3350 const void *v;
3351 const FLOAT *fl;
3352 } data = { pPropData };
3354 prim->eax_prop.flEnvironmentDiffusion = *data.fl;
3355 alEffectf(prim->effect, AL_REVERB_DIFFUSION,
3356 prim->eax_prop.flEnvironmentDiffusion);
3357 checkALError();
3359 prim->dirty.bit.effect = 1;
3360 hr = DS_OK;
3362 break;
3364 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
3365 if(cbPropData >= sizeof(FLOAT))
3367 union {
3368 const void *v;
3369 const FLOAT *fl;
3370 } data = { pPropData };
3372 prim->eax_prop.flAirAbsorptionHF = *data.fl;
3373 alEffectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
3374 mB_to_gain(prim->eax_prop.flAirAbsorptionHF));
3375 checkALError();
3377 prim->dirty.bit.effect = 1;
3378 hr = DS_OK;
3380 break;
3382 case DSPROPERTY_EAXLISTENER_FLAGS:
3383 if(cbPropData >= sizeof(DWORD))
3385 union {
3386 const void *v;
3387 const DWORD *dw;
3388 } data = { pPropData };
3390 prim->eax_prop.dwFlags = *data.dw;
3391 alEffecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
3392 (prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
3393 AL_TRUE : AL_FALSE);
3394 checkALError();
3396 prim->dirty.bit.effect = 1;
3397 hr = DS_OK;
3399 break;
3401 default:
3402 hr = E_PROP_ID_UNSUPPORTED;
3403 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
3404 break;
3407 if(hr == DS_OK && immediate)
3408 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
3410 popALContext();
3411 LeaveCriticalSection(prim->crst);
3413 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX_ReverbProperties))
3415 static const float eax1_env_dampening[EAX_ENVIRONMENT_COUNT] = {
3416 0.5f, 0.0f, 0.666f, 0.166f, 0.0f, 0.888f, 0.5f, 0.5f, 1.304f,
3417 0.332f, 0.3f, 2.0f, 0.0f, 0.638f, 0.776f, 0.472f, 0.224f, 0.472f,
3418 0.5f, 0.224f, 1.5f, 0.25f, 0.0f, 1.388f, 0.666f, 0.806f
3420 DS8Primary *prim = This->primary;
3421 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
3422 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
3424 EnterCriticalSection(prim->crst);
3425 setALContext(prim->ctx);
3427 hr = DSERR_INVALIDPARAM;
3428 if(prim->effect == 0)
3429 hr = E_PROP_ID_UNSUPPORTED;
3430 else switch(propid)
3432 case DSPROPERTY_EAX1_ALL:
3433 if(cbPropData >= sizeof(EAX1_REVERBPROPERTIES))
3435 union {
3436 const void *v;
3437 const EAX1_REVERBPROPERTIES *props;
3438 } data = { pPropData };
3440 if(data.props->dwEnvironment < EAX_ENVIRONMENT_COUNT)
3442 EAX20LISTENERPROPERTIES env = EnvironmentDefaults[data.props->dwEnvironment];
3443 env.lRoom = gain_to_mB(data.props->fVolume);
3444 env.flDecayTime = data.props->fDecayTime;
3445 prim->eax1_dampening = data.props->fDamping;
3446 ApplyReverbParams(prim, &env);
3447 hr = DS_OK;
3450 break;
3452 case DSPROPERTY_EAX1_ENVIRONMENT:
3453 if(cbPropData >= sizeof(DWORD))
3455 union {
3456 const void *v;
3457 const DWORD *dw;
3458 } data = { pPropData };
3460 if(*data.dw < EAX_ENVIRONMENT_COUNT)
3462 prim->eax1_dampening = eax1_env_dampening[*data.dw];
3463 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
3464 hr = DS_OK;
3467 break;
3469 case DSPROPERTY_EAX1_VOLUME:
3470 if(cbPropData >= sizeof(FLOAT))
3472 union {
3473 const void *v;
3474 const FLOAT *l;
3475 } data = { pPropData };
3477 prim->eax_prop.lRoom = gain_to_mB(*data.l);
3478 alEffectf(prim->effect, AL_REVERB_GAIN,
3479 mB_to_gain(prim->eax_prop.lRoom));
3480 checkALError();
3482 prim->dirty.bit.effect = 1;
3483 hr = DS_OK;
3485 break;
3486 case DSPROPERTY_EAX1_DECAYTIME:
3487 if(cbPropData >= sizeof(FLOAT))
3489 union {
3490 const void *v;
3491 const FLOAT *fl;
3492 } data = { pPropData };
3494 prim->eax_prop.flDecayTime = *data.fl;
3495 alEffectf(prim->effect, AL_REVERB_DECAY_TIME,
3496 prim->eax_prop.flDecayTime);
3497 checkALError();
3499 prim->dirty.bit.effect = 1;
3500 hr = DS_OK;
3502 break;
3503 case DSPROPERTY_EAX1_DAMPING:
3504 if(cbPropData >= sizeof(FLOAT))
3506 union {
3507 const void *v;
3508 const FLOAT *fl;
3509 } data = { pPropData };
3511 prim->eax1_dampening = *data.fl;
3513 hr = DS_OK;
3515 break;
3517 default:
3518 hr = E_PROP_ID_UNSUPPORTED;
3519 FIXME("Unhandled EAX1 listener propid: 0x%08lx\n", propid);
3520 break;
3523 if(hr == DS_OK && immediate)
3524 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
3526 popALContext();
3527 LeaveCriticalSection(prim->crst);
3529 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAXBUFFER_ReverbProperties))
3531 DWORD propid = dwPropID & ~DSPROPERTY_EAXBUFFER_DEFERRED;
3532 BOOL immediate = !(dwPropID&DSPROPERTY_EAXBUFFER_DEFERRED);
3534 EnterCriticalSection(This->crst);
3535 setALContext(This->ctx);
3537 hr = DSERR_INVALIDPARAM;
3538 if(This->filter[0] == 0)
3539 hr = E_PROP_ID_UNSUPPORTED;
3540 else switch(propid)
3542 case DSPROPERTY_EAX1BUFFER_ALL:
3543 case DSPROPERTY_EAX1BUFFER_REVERBMIX:
3544 if(cbPropData >= sizeof(FLOAT))
3546 union {
3547 const void *v;
3548 const FLOAT *props;
3549 } data = { pPropData };
3551 This->eax_prop.lRoom = gain_to_mB(*data.props);
3552 ApplyFilterParams(This, &This->eax_prop, APPLY_WET_PARAMS);
3554 This->dirty.bit.wet_filter = 1;
3555 hr = DS_OK;
3557 break;
3559 default:
3560 hr = E_PROP_ID_UNSUPPORTED;
3561 FIXME("Unhandled EAX1 buffer propid: 0x%08lx\n", propid);
3562 break;
3565 if(hr == DS_OK && immediate)
3566 DS8Primary3D_CommitDeferredSettings(&This->primary->IDirectSound3DListener_iface);
3568 popALContext();
3569 LeaveCriticalSection(This->crst);
3571 else
3572 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
3574 return hr;
3577 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
3578 REFGUID guidPropSet, ULONG dwPropID,
3579 ULONG *pTypeSupport)
3581 DS8Buffer *This = impl_from_IKsPropertySet(iface);
3582 HRESULT hr = E_PROP_ID_UNSUPPORTED;
3584 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
3586 if(!pTypeSupport)
3587 return E_POINTER;
3588 *pTypeSupport = 0;
3590 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
3592 EnterCriticalSection(This->crst);
3594 if(This->filter[0] == 0)
3595 hr = E_PROP_ID_UNSUPPORTED;
3596 else switch(dwPropID)
3598 case DSPROPERTY_EAXBUFFER_NONE:
3599 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
3600 hr = DS_OK;
3601 break;
3602 case DSPROPERTY_EAXBUFFER_ALLPARAMETERS:
3603 case DSPROPERTY_EAXBUFFER_DIRECT:
3604 case DSPROPERTY_EAXBUFFER_DIRECTHF:
3605 case DSPROPERTY_EAXBUFFER_ROOM:
3606 case DSPROPERTY_EAXBUFFER_ROOMHF:
3607 case DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR:
3608 case DSPROPERTY_EAXBUFFER_OBSTRUCTION:
3609 case DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO:
3610 case DSPROPERTY_EAXBUFFER_OCCLUSION:
3611 case DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO:
3612 case DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO:
3613 case DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF:
3614 case DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR:
3615 case DSPROPERTY_EAXBUFFER_FLAGS:
3616 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
3617 hr = DS_OK;
3618 break;
3619 default:
3620 hr = E_PROP_ID_UNSUPPORTED;
3621 FIXME("Unhandled EAX2 buffer propid: 0x%08lx\n", dwPropID);
3622 break;
3625 LeaveCriticalSection(This->crst);
3627 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
3629 DS8Primary *prim = This->primary;
3631 EnterCriticalSection(This->crst);
3633 if(prim->effect == 0)
3634 hr = E_PROP_ID_UNSUPPORTED;
3635 else switch(dwPropID)
3637 case DSPROPERTY_EAXLISTENER_NONE:
3638 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
3639 hr = DS_OK;
3640 break;
3641 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
3642 case DSPROPERTY_EAXLISTENER_ROOM:
3643 case DSPROPERTY_EAXLISTENER_ROOMHF:
3644 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
3645 case DSPROPERTY_EAXLISTENER_DECAYTIME:
3646 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
3647 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
3648 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
3649 case DSPROPERTY_EAXLISTENER_REVERB:
3650 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
3651 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
3652 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
3653 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
3654 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
3655 case DSPROPERTY_EAXLISTENER_FLAGS:
3656 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
3657 hr = DS_OK;
3658 break;
3659 default:
3660 hr = E_PROP_ID_UNSUPPORTED;
3661 FIXME("Unhandled EAX2 listener propid: 0x%08lx\n", dwPropID);
3662 break;
3665 LeaveCriticalSection(This->crst);
3667 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX_ReverbProperties))
3669 DS8Primary *prim = This->primary;
3671 EnterCriticalSection(This->crst);
3673 if(prim->effect == 0)
3674 hr = E_PROP_ID_UNSUPPORTED;
3675 else switch(dwPropID)
3677 case DSPROPERTY_EAX1_ALL:
3678 case DSPROPERTY_EAX1_ENVIRONMENT:
3679 case DSPROPERTY_EAX1_VOLUME:
3680 case DSPROPERTY_EAX1_DECAYTIME:
3681 case DSPROPERTY_EAX1_DAMPING:
3682 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
3683 hr = DS_OK;
3684 break;
3685 default:
3686 hr = E_PROP_ID_UNSUPPORTED;
3687 FIXME("Unhandled EAX1 listener propid: 0x%08lx\n", dwPropID);
3688 break;
3691 LeaveCriticalSection(This->crst);
3693 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAXBUFFER_ReverbProperties))
3695 EnterCriticalSection(This->crst);
3697 if(This->filter[0] == 0)
3698 hr = E_PROP_ID_UNSUPPORTED;
3699 else switch(dwPropID)
3701 case DSPROPERTY_EAX1BUFFER_ALL:
3702 case DSPROPERTY_EAX1BUFFER_REVERBMIX:
3703 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
3704 hr = DS_OK;
3705 break;
3706 default:
3707 hr = E_PROP_ID_UNSUPPORTED;
3708 FIXME("Unhandled EAX1 buffer propid: 0x%08lx\n", dwPropID);
3709 break;
3712 LeaveCriticalSection(This->crst);
3714 else
3715 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
3717 return hr;
3720 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
3722 DS8BufferProp_QueryInterface,
3723 DS8BufferProp_AddRef,
3724 DS8BufferProp_Release,
3725 DS8BufferProp_Get,
3726 DS8BufferProp_Set,
3727 DS8BufferProp_QuerySupport