Partially handle EAX buffer properties
[dsound-openal.git] / buffer.c
blob488ac02f03e04e9ae6b4e6861c927fb92f487ab9
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 !prim->SupportedExt[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 !prim->SupportedExt[EXT_MCFORMATS])
167 WARN("Multi-channel not available\n");
168 return NULL;
171 if(format->wBitsPerSample == 32 && prim->SupportedExt[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 !prim->SupportedExt[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 prim->SupportedExt[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(!prim->SupportedExt[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 pBuffer->buf_format = alGetEnumValue(fmt_str);
397 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
398 pBuffer->buf_format == -1)
400 WARN("Could not get OpenAL format from %s\n", fmt_str);
401 goto fail;
404 hr = E_OUTOFMEMORY;
405 if(!prim->SupportedExt[SOFTX_MAP_BUFFER])
407 pBuffer->data = (BYTE*)(pBuffer+1);
409 alGenBuffers(1, &pBuffer->bid);
410 checkALError();
412 else
414 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
415 AL_MAP_PERSISTENT_BIT_SOFT;
416 alGenBuffers(1, &pBuffer->bid);
417 prim->ExtAL->BufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
418 pBuffer->format.Format.nSamplesPerSec, map_bits);
419 pBuffer->data = prim->ExtAL->MapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
420 checkALError();
422 if(!pBuffer->data) goto fail;
425 *ppv = pBuffer;
426 return S_OK;
428 fail:
429 DS8Data_Release(pBuffer);
430 return hr;
433 static void DS8Data_AddRef(DS8Data *data)
435 InterlockedIncrement(&data->ref);
438 /* This function is always called with the device lock held */
439 static void DS8Data_Release(DS8Data *This)
441 if(InterlockedDecrement(&This->ref)) return;
443 TRACE("Deleting %p\n", This);
444 if(This->bid)
446 DS8Primary *prim = This->primary;
447 if(prim->SupportedExt[SOFTX_MAP_BUFFER])
448 prim->ExtAL->UnmapBufferSOFT(This->bid);
449 alDeleteBuffers(1, &This->bid);
450 checkALError();
452 HeapFree(GetProcessHeap(), 0, This);
456 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig, BOOL prim_emu)
458 DS8Buffer *This = NULL;
459 HRESULT hr;
460 DWORD i;
462 *ppv = NULL;
463 EnterCriticalSection(prim->crst);
464 if(prim_emu)
466 This = &prim->writable_buf;
467 memset(This, 0, sizeof(*This));
469 else for(i = 0;i < prim->NumBufferGroups;++i)
471 if(prim->BufferGroups[i].FreeBuffers)
473 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
474 This = prim->BufferGroups[i].Buffers + idx;
475 memset(This, 0, sizeof(*This));
476 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
477 break;
480 LeaveCriticalSection(prim->crst);
481 if(!This)
483 WARN("Out of buffers\n");
484 return DSERR_ALLOCATED;
487 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
488 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
489 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
490 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
492 This->primary = prim;
493 This->ctx = prim->ctx;
494 This->ExtAL = prim->ExtAL;
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[prim->parent->share->nsources++] = This->source;
546 This->source = 0;
548 if(This->stream_bids[0])
549 alDeleteBuffers(QBUFFERS, This->stream_bids);
550 if(This->filter[0])
551 prim->ExtAL->DeleteFilters(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 if(!This->buffer)
945 hr = DSERR_INVALIDPARAM;
946 if(!desc)
948 WARN("Missing DSound buffer description\n");
949 goto out;
951 if(!desc->lpwfxFormat)
953 WARN("Missing buffer format (%p)\n", This);
954 goto out;
956 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
958 if(This->primary->parent->is_8)
960 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
961 * buffers */
962 WARN("Can't create multi-channel 3D buffers\n");
963 goto out;
965 else
967 static int once = 0;
968 if(!once++)
969 ERR("Multi-channel 3D sounds are not spatialized\n");
972 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
974 static int once = 0;
975 if(!once++)
976 ERR("Panning for multi-channel buffers is not supported\n");
979 hr = DS8Data_Create(&This->buffer, desc, This->primary);
980 if(FAILED(hr)) goto out;
982 data = This->buffer;
983 if(data->format.Format.wBitsPerSample == 8)
984 memset(data->data, 0x80, data->buf_size);
985 else
986 memset(data->data, 0x00, data->buf_size);
989 prim = This->primary;
990 data = This->buffer;
991 if(!(data->dsbflags&DSBCAPS_STATIC) && !prim->SupportedExt[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->parent->share->nsources)
1004 goto out;
1006 This->source = prim->sources[--(prim->parent->share->nsources)];
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 = 1.0f;
1037 eaxbuffer->lOcclusion = 0;
1038 eaxbuffer->flOcclusionLFRatio = 1.0f;
1039 eaxbuffer->flOcclusionRoomRatio = 1.0f;
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(prim->SupportedExt[EXT_EFX])
1051 prim->ExtAL->GenFilters(2, This->filter);
1052 prim->ExtAL->Filteri(This->filter[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS);
1053 prim->ExtAL->Filteri(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(prim->SupportedExt[EXT_EFX])
1066 dirty.bit.dry_filter = 1;
1067 dirty.bit.wet_filter = 1;
1068 dirty.bit.room_rolloff = 1;
1069 dirty.bit.out_cone_vol = 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(prim->SupportedExt[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 /* Simple hack to make reverb affect non-3D sounds too */
1102 alSource3i(source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, AL_FILTER_NULL);
1103 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1105 checkALError();
1107 hr = S_OK;
1109 out:
1110 popALContext();
1111 LeaveCriticalSection(This->crst);
1113 return hr;
1116 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1118 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1119 DWORD remain;
1121 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1123 if(!ptr1 || !len1)
1125 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1126 return DSERR_INVALIDPARAM;
1129 *ptr1 = NULL;
1130 *len1 = 0;
1131 if(ptr2) *ptr2 = NULL;
1132 if(len2) *len2 = 0;
1134 if((flags&DSBLOCK_FROMWRITECURSOR))
1135 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1136 else if(ofs >= (DWORD)This->buffer->buf_size)
1138 WARN("Invalid ofs %lu\n", ofs);
1139 return DSERR_INVALIDPARAM;
1141 if((flags&DSBLOCK_ENTIREBUFFER))
1142 bytes = This->buffer->buf_size;
1143 else if(bytes > (DWORD)This->buffer->buf_size)
1145 WARN("Invalid size %lu\n", bytes);
1146 return DSERR_INVALIDPARAM;
1149 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1151 WARN("Already locked\n");
1152 return DSERR_INVALIDPARAM;
1155 *ptr1 = This->buffer->data + ofs;
1156 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1158 *len1 = This->buffer->buf_size - ofs;
1159 remain = bytes - *len1;
1161 else
1163 *len1 = bytes;
1164 remain = 0;
1167 if(ptr2 && len2 && remain)
1169 *ptr2 = This->buffer->data;
1170 *len2 = remain;
1173 return DS_OK;
1176 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1178 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1179 ALint state = AL_STOPPED;
1180 DS8Data *data;
1181 HRESULT hr;
1183 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1185 EnterCriticalSection(This->crst);
1186 setALContext(This->ctx);
1188 hr = DSERR_BUFFERLOST;
1189 if(This->bufferlost)
1191 WARN("Buffer %p lost\n", This);
1192 goto out;
1195 data = This->buffer;
1196 if((data->dsbflags&DSBCAPS_LOCDEFER))
1198 if(!(data->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1200 if(flags & DSBPLAY_LOCSOFTWARE)
1201 data->dsbflags |= DSBCAPS_LOCSOFTWARE;
1202 else
1203 data->dsbflags |= DSBCAPS_LOCHARDWARE;
1206 else if(prio)
1208 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1209 hr = DSERR_INVALIDPARAM;
1210 goto out;
1213 if(This->segsize != 0)
1215 This->islooping = !!(flags&DSBPLAY_LOOPING);
1216 if(This->isplaying) state = AL_PLAYING;
1218 else
1220 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1221 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1223 checkALError();
1225 hr = S_OK;
1226 if(state == AL_PLAYING)
1227 goto out;
1229 if(This->segsize == 0)
1231 if(state != AL_PAUSED)
1232 alSourcei(This->source, AL_BUFFER, data->bid);
1233 alSourcePlay(This->source);
1235 else
1237 alSourceRewind(This->source);
1238 alSourcei(This->source, AL_BUFFER, 0);
1239 This->queue_base = This->data_offset % data->buf_size;
1240 This->curidx = 0;
1242 if(alGetError() != AL_NO_ERROR)
1244 ERR("Couldn't start source\n");
1245 alSourcei(This->source, AL_BUFFER, 0);
1246 checkALError();
1247 hr = DSERR_GENERIC;
1248 goto out;
1250 This->isplaying = TRUE;
1251 This->playflags = flags;
1253 if(This->nnotify)
1254 DS8Buffer_addnotify(This);
1256 out:
1257 popALContext();
1258 LeaveCriticalSection(This->crst);
1259 return hr;
1262 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1264 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1265 DS8Data *data;
1267 TRACE("(%p)->(%lu)\n", iface, pos);
1269 data = This->buffer;
1270 if(pos >= (DWORD)data->buf_size)
1271 return DSERR_INVALIDPARAM;
1272 pos -= pos%data->format.Format.nBlockAlign;
1274 EnterCriticalSection(This->crst);
1276 if(This->segsize != 0)
1278 if(This->isplaying)
1280 setALContext(This->ctx);
1281 /* Perform a flush, so the next timer update will restart at the
1282 * proper position */
1283 alSourceRewind(This->source);
1284 alSourcei(This->source, AL_BUFFER, 0);
1285 checkALError();
1286 popALContext();
1288 This->queue_base = This->data_offset = pos;
1289 This->curidx = 0;
1291 else
1293 setALContext(This->ctx);
1294 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1295 popALContext();
1297 This->lastpos = pos;
1299 LeaveCriticalSection(This->crst);
1300 return DS_OK;
1303 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1305 /* This call only works on primary buffers */
1306 WARN("(%p)->(%p)\n", iface, wfx);
1307 return DSERR_INVALIDCALL;
1310 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1312 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1313 HRESULT hr = S_OK;
1315 TRACE("(%p)->(%ld)\n", iface, vol);
1317 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1319 WARN("Invalid volume (%ld)\n", vol);
1320 return DSERR_INVALIDPARAM;
1323 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1324 hr = DSERR_CONTROLUNAVAIL;
1325 if(SUCCEEDED(hr))
1327 ALfloat fvol = mB_to_gain(vol);
1328 setALContext(This->ctx);
1329 alSourcef(This->source, AL_GAIN, fvol);
1330 popALContext();
1333 return hr;
1336 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1338 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1339 HRESULT hr = S_OK;
1341 TRACE("(%p)->(%ld)\n", iface, pan);
1343 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1345 WARN("invalid parameter: pan = %ld\n", pan);
1346 return DSERR_INVALIDPARAM;
1349 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1350 hr = DSERR_CONTROLUNAVAIL;
1351 else
1353 if(!(This->buffer->dsbflags&DSBCAPS_CTRL3D))
1355 ALfloat pos[3];
1356 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1357 pos[1] = 0.0f;
1358 /* NOTE: Strict movement along the X plane can cause the sound to
1359 * jump between left and right sharply. Using a curved path helps
1360 * smooth it out.
1362 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1364 setALContext(This->ctx);
1365 alSourcefv(This->source, AL_POSITION, pos);
1366 checkALError();
1367 popALContext();
1371 return hr;
1374 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1376 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1377 HRESULT hr = S_OK;
1379 TRACE("(%p)->(%lu)\n", iface, freq);
1381 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1383 WARN("invalid parameter: freq = %lu\n", freq);
1384 return DSERR_INVALIDPARAM;
1387 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1388 hr = DSERR_CONTROLUNAVAIL;
1389 else
1391 ALfloat pitch = 1.0f;
1392 if(freq != DSBFREQUENCY_ORIGINAL)
1393 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1395 setALContext(This->ctx);
1396 alSourcef(This->source, AL_PITCH, pitch);
1397 checkALError();
1398 popALContext();
1401 return hr;
1404 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1406 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1408 TRACE("(%p)->()\n", iface);
1410 EnterCriticalSection(This->crst);
1411 setALContext(This->ctx);
1413 alSourcePause(This->source);
1414 checkALError();
1416 This->isplaying = FALSE;
1417 DS8Primary_triggernots(This->primary);
1419 popALContext();
1420 LeaveCriticalSection(This->crst);
1422 return S_OK;
1425 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1427 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1428 DS8Data *buf = This->buffer;
1429 DWORD bufsize = buf->buf_size;
1430 DWORD_PTR ofs1, ofs2;
1431 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1432 HRESULT hr;
1434 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1436 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1438 WARN("Not locked\n");
1439 return DSERR_INVALIDPARAM;
1442 hr = DSERR_INVALIDPARAM;
1443 /* Make sure offset is between boundary and boundary + bufsize */
1444 ofs1 = (DWORD_PTR)ptr1;
1445 ofs2 = (DWORD_PTR)ptr2;
1446 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1447 goto out;
1448 ofs1 -= boundary;
1449 ofs2 = 0;
1450 if(bufsize-ofs1 < len1 || len2 > ofs1)
1451 goto out;
1452 if(!ptr2)
1453 len2 = 0;
1455 hr = DS_OK;
1456 if(!len1 && !len2)
1457 goto out;
1459 if(This->primary->SupportedExt[SOFTX_MAP_BUFFER])
1461 setALContext(This->ctx);
1462 This->ExtAL->FlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1463 checkALError();
1464 popALContext();
1466 else if(This->segsize == 0)
1468 setALContext(This->ctx);
1469 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1470 buf->format.Format.nSamplesPerSec);
1471 checkALError();
1472 popALContext();
1475 out:
1476 if(hr != S_OK)
1477 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1478 return hr;
1481 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1483 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1484 HRESULT hr;
1486 TRACE("(%p)->()\n", iface);
1488 EnterCriticalSection(This->crst);
1489 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1490 iface == This->primary->write_emu)
1492 This->bufferlost = 0;
1493 hr = S_OK;
1495 else
1496 hr = DSERR_BUFFERLOST;
1497 LeaveCriticalSection(This->crst);
1499 return hr;
1502 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1504 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1505 ALenum state = AL_INITIAL;
1506 DS8Data *data;
1507 HRESULT hr;
1508 DWORD i;
1510 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1512 data = This->buffer;
1513 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1515 WARN("FX control not set\n");
1516 return DSERR_CONTROLUNAVAIL;
1519 if(data->locked)
1521 WARN("Buffer is locked\n");
1522 return DSERR_INVALIDCALL;
1525 EnterCriticalSection(This->crst);
1526 setALContext(This->ctx);
1528 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1529 checkALError();
1530 if(This->segsize != 0 && state != AL_PLAYING)
1531 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1532 if(state == AL_PLAYING)
1534 WARN("Buffer is playing\n");
1535 hr = DSERR_INVALIDCALL;
1536 goto done;
1539 hr = DSERR_INVALIDPARAM;
1540 if(fxcount == 0)
1542 if(desc || rescodes)
1544 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1545 goto done;
1548 /* No effects; we can handle that */
1549 hr = DS_OK;
1550 goto done;
1553 if(!desc || !rescodes)
1555 WARN("NULL desc and/or result pointer specified.\n");
1556 goto done;
1559 /* We don't (currently) handle DSound effects */
1560 for(i = 0;i < fxcount;++i)
1562 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1563 rescodes[i] = DSFXR_FAILED;
1565 hr = DS_INCOMPLETE;
1567 done:
1568 popALContext();
1569 LeaveCriticalSection(This->crst);
1571 return hr;
1574 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1576 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1578 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1580 /* effects aren't supported at the moment.. */
1581 if(fxcount != 0 || rescodes)
1583 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1584 return DSERR_INVALIDPARAM;
1587 EnterCriticalSection(This->crst);
1588 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1590 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1591 if((flags&DSBPLAY_LOCSOFTWARE))
1592 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1593 else
1594 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1596 LeaveCriticalSection(This->crst);
1598 return S_OK;
1601 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1603 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1604 return E_NOTIMPL;
1607 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1608 DS8Buffer_QueryInterface,
1609 DS8Buffer_AddRef,
1610 DS8Buffer_Release,
1611 DS8Buffer_GetCaps,
1612 DS8Buffer_GetCurrentPosition,
1613 DS8Buffer_GetFormat,
1614 DS8Buffer_GetVolume,
1615 DS8Buffer_GetPan,
1616 DS8Buffer_GetFrequency,
1617 DS8Buffer_GetStatus,
1618 DS8Buffer_Initialize,
1619 DS8Buffer_Lock,
1620 DS8Buffer_Play,
1621 DS8Buffer_SetCurrentPosition,
1622 DS8Buffer_SetFormat,
1623 DS8Buffer_SetVolume,
1624 DS8Buffer_SetPan,
1625 DS8Buffer_SetFrequency,
1626 DS8Buffer_Stop,
1627 DS8Buffer_Unlock,
1628 DS8Buffer_Restore,
1629 DS8Buffer_SetFX,
1630 DS8Buffer_AcquireResources,
1631 DS8Buffer_GetObjectInPath
1635 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, const EAX20BUFFERPROPERTIES *eax_params, LONG flags)
1637 const ALuint source = This->source;
1638 union BufferParamFlags dirty = { flags };
1640 if(dirty.bit.pos)
1641 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1642 -params->vPosition.z);
1643 if(dirty.bit.vel)
1644 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1645 -params->vVelocity.z);
1646 if(dirty.bit.cone_angles)
1648 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1649 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1651 if(dirty.bit.cone_orient)
1652 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1653 params->vConeOrientation.y,
1654 -params->vConeOrientation.z);
1655 if(dirty.bit.cone_outsidevolume)
1656 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1657 if(dirty.bit.min_distance)
1658 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1659 if(dirty.bit.max_distance)
1660 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1661 if(dirty.bit.mode)
1663 This->ds3dmode = params->dwMode;
1664 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1665 AL_TRUE : AL_FALSE);
1666 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1667 0.0f : This->primary->rollofffactor);
1670 if(dirty.bit.dry_filter)
1671 alSourcei(source, AL_DIRECT_FILTER, This->filter[0]);
1672 if(dirty.bit.wet_filter)
1673 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, This->filter[1]);
1674 if(dirty.bit.room_rolloff)
1675 alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, eax_params->flRoomRolloffFactor);
1676 if(dirty.bit.out_cone_vol)
1677 alSourcef(source, AL_CONE_OUTER_GAINHF, mB_to_gain(eax_params->lOutsideVolumeHF));
1678 if(dirty.bit.air_absorb)
1679 alSourcef(source, AL_AIR_ABSORPTION_FACTOR, eax_params->flAirAbsorptionFactor);
1680 if(dirty.bit.flags)
1682 alSourcei(source, AL_DIRECT_FILTER_GAINHF_AUTO,
1683 (eax_params->dwFlags&EAXBUFFERFLAGS_DIRECTHFAUTO) ? AL_TRUE : AL_FALSE);
1684 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
1685 (eax_params->dwFlags&EAXBUFFERFLAGS_ROOMAUTO) ? AL_TRUE : AL_FALSE);
1686 alSourcei(source, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
1687 (eax_params->dwFlags&EAXBUFFERFLAGS_ROOMHFAUTO) ? AL_TRUE : AL_FALSE);
1691 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1693 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1694 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1697 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1699 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1700 LONG ret;
1702 InterlockedIncrement(&This->all_ref);
1703 ret = InterlockedIncrement(&This->ds3d_ref);
1704 TRACE("new refcount %ld\n", ret);
1706 return ret;
1709 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1711 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1712 LONG ret;
1714 ret = InterlockedDecrement(&This->ds3d_ref);
1715 TRACE("new refcount %ld\n", ret);
1716 if(InterlockedDecrement(&This->all_ref) == 0)
1717 DS8Buffer_Destroy(This);
1719 return ret;
1722 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1724 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1725 ALint inangle, outangle;
1727 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1728 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1730 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1731 return DSERR_INVALIDPARAM;
1734 EnterCriticalSection(This->crst);
1735 setALContext(This->ctx);
1737 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1738 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1739 checkALError();
1741 popALContext();
1742 LeaveCriticalSection(This->crst);
1744 *pdwInsideConeAngle = inangle;
1745 *pdwOutsideConeAngle = outangle;
1746 return S_OK;
1749 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1751 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1752 ALfloat dir[3];
1754 TRACE("(%p)->(%p)\n", This, orient);
1755 if(!orient)
1757 WARN("Invalid pointer\n");
1758 return DSERR_INVALIDPARAM;
1761 setALContext(This->ctx);
1762 alGetSourcefv(This->source, AL_DIRECTION, dir);
1763 checkALError();
1764 popALContext();
1766 orient->x = dir[0];
1767 orient->y = dir[1];
1768 orient->z = -dir[2];
1769 return S_OK;
1772 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1774 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1775 ALfloat gain;
1777 TRACE("(%p)->(%p)\n", This, vol);
1778 if(!vol)
1780 WARN("Invalid pointer\n");
1781 return DSERR_INVALIDPARAM;
1784 setALContext(This->ctx);
1785 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1786 checkALError();
1787 popALContext();
1789 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1790 return S_OK;
1793 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1795 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1796 ALfloat dist;
1798 TRACE("(%p)->(%p)\n", This, maxdist);
1799 if(!maxdist)
1801 WARN("Invalid pointer\n");
1802 return DSERR_INVALIDPARAM;
1805 setALContext(This->ctx);
1806 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1807 checkALError();
1808 popALContext();
1810 *maxdist = dist;
1811 return S_OK;
1814 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1816 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1817 ALfloat dist;
1819 TRACE("(%p)->(%p)\n", This, mindist);
1820 if(!mindist)
1822 WARN("Invalid pointer\n");
1823 return DSERR_INVALIDPARAM;
1826 setALContext(This->ctx);
1827 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1828 checkALError();
1829 popALContext();
1831 *mindist = dist;
1832 return S_OK;
1835 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1837 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1839 TRACE("(%p)->(%p)\n", This, mode);
1840 if(!mode)
1842 WARN("Invalid pointer\n");
1843 return DSERR_INVALIDPARAM;
1846 EnterCriticalSection(This->crst);
1847 *mode = This->ds3dmode;
1848 LeaveCriticalSection(This->crst);
1850 return S_OK;
1853 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1855 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1856 ALfloat alpos[3];
1858 TRACE("(%p)->(%p)\n", This, pos);
1859 if(!pos)
1861 WARN("Invalid pointer\n");
1862 return DSERR_INVALIDPARAM;
1865 setALContext(This->ctx);
1866 alGetSourcefv(This->source, AL_POSITION, alpos);
1867 checkALError();
1868 popALContext();
1870 pos->x = alpos[0];
1871 pos->y = alpos[1];
1872 pos->z = -alpos[2];
1873 return S_OK;
1876 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1878 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1879 ALfloat alvel[3];
1881 TRACE("(%p)->(%p)\n", This, vel);
1882 if(!vel)
1884 WARN("Invalid pointer\n");
1885 return DSERR_INVALIDPARAM;
1888 setALContext(This->ctx);
1889 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1890 checkALError();
1891 popALContext();
1893 vel->x = alvel[0];
1894 vel->y = alvel[1];
1895 vel->z = -alvel[2];
1896 return S_OK;
1899 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1901 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1903 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1905 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1907 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1908 return DSERR_INVALIDPARAM;
1911 EnterCriticalSection(This->crst);
1912 setALContext(This->ctx);
1914 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1915 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1916 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1917 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1918 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1919 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1920 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
1921 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
1923 popALContext();
1924 LeaveCriticalSection(This->crst);
1926 return DS_OK;
1929 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
1931 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1933 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
1934 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
1935 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
1937 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
1938 return DSERR_INVALIDPARAM;
1941 EnterCriticalSection(This->crst);
1942 if(apply == DS3D_DEFERRED)
1944 This->params.dwInsideConeAngle = dwInsideConeAngle;
1945 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
1946 This->dirty.bit.cone_angles = 1;
1948 else
1950 setALContext(This->ctx);
1951 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
1952 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
1953 checkALError();
1954 popALContext();
1956 LeaveCriticalSection(This->crst);
1958 return S_OK;
1961 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1963 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1965 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
1967 if(apply == DS3D_DEFERRED)
1969 EnterCriticalSection(This->crst);
1970 This->params.vConeOrientation.x = x;
1971 This->params.vConeOrientation.y = y;
1972 This->params.vConeOrientation.z = z;
1973 This->dirty.bit.cone_orient = 1;
1974 LeaveCriticalSection(This->crst);
1976 else
1978 setALContext(This->ctx);
1979 alSource3f(This->source, AL_DIRECTION, x, y, -z);
1980 checkALError();
1981 popALContext();
1984 return S_OK;
1987 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
1989 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1991 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
1992 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
1994 WARN("Invalid volume (%ld)\n", vol);
1995 return DSERR_INVALIDPARAM;
1998 if(apply == DS3D_DEFERRED)
2000 EnterCriticalSection(This->crst);
2001 This->params.lConeOutsideVolume = vol;
2002 This->dirty.bit.cone_outsidevolume = 1;
2003 LeaveCriticalSection(This->crst);
2005 else
2007 setALContext(This->ctx);
2008 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2009 checkALError();
2010 popALContext();
2013 return S_OK;
2016 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2018 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2020 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2021 if(maxdist < 0.0f)
2023 WARN("Invalid max distance (%f)\n", maxdist);
2024 return DSERR_INVALIDPARAM;
2027 if(apply == DS3D_DEFERRED)
2029 EnterCriticalSection(This->crst);
2030 This->params.flMaxDistance = maxdist;
2031 This->dirty.bit.max_distance = 1;
2032 LeaveCriticalSection(This->crst);
2034 else
2036 setALContext(This->ctx);
2037 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2038 checkALError();
2039 popALContext();
2042 return S_OK;
2045 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2047 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2049 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2050 if(mindist < 0.0f)
2052 WARN("Invalid min distance (%f)\n", mindist);
2053 return DSERR_INVALIDPARAM;
2056 if(apply == DS3D_DEFERRED)
2058 EnterCriticalSection(This->crst);
2059 This->params.flMinDistance = mindist;
2060 This->dirty.bit.min_distance = 1;
2061 LeaveCriticalSection(This->crst);
2063 else
2065 setALContext(This->ctx);
2066 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2067 checkALError();
2068 popALContext();
2071 return S_OK;
2074 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2076 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2078 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2079 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2080 mode != DS3DMODE_DISABLE)
2082 WARN("Invalid mode (%lu)\n", mode);
2083 return DSERR_INVALIDPARAM;
2086 EnterCriticalSection(This->crst);
2087 if(apply == DS3D_DEFERRED)
2089 This->params.dwMode = mode;
2090 This->dirty.bit.mode = 1;
2092 else
2094 setALContext(This->ctx);
2095 alSourcei(This->source, AL_SOURCE_RELATIVE,
2096 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2097 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2098 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2099 This->ds3dmode = mode;
2100 checkALError();
2101 popALContext();
2103 LeaveCriticalSection(This->crst);
2105 return S_OK;
2108 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2110 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2112 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2114 if(apply == DS3D_DEFERRED)
2116 EnterCriticalSection(This->crst);
2117 This->params.vPosition.x = x;
2118 This->params.vPosition.y = y;
2119 This->params.vPosition.z = z;
2120 This->dirty.bit.pos = 1;
2121 LeaveCriticalSection(This->crst);
2123 else
2125 setALContext(This->ctx);
2126 alSource3f(This->source, AL_POSITION, x, y, -z);
2127 checkALError();
2128 popALContext();
2131 return S_OK;
2134 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2136 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2138 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2140 if(apply == DS3D_DEFERRED)
2142 EnterCriticalSection(This->crst);
2143 This->params.vVelocity.x = x;
2144 This->params.vVelocity.y = y;
2145 This->params.vVelocity.z = z;
2146 This->dirty.bit.vel = 1;
2147 LeaveCriticalSection(This->crst);
2149 else
2151 setALContext(This->ctx);
2152 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2153 checkALError();
2154 popALContext();
2157 return S_OK;
2160 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2162 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2163 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2165 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2167 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2168 return DSERR_INVALIDPARAM;
2171 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2172 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2174 WARN("Invalid cone angles (%lu, %lu)\n",
2175 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2176 return DSERR_INVALIDPARAM;
2179 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2180 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2182 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2183 return DSERR_INVALIDPARAM;
2186 if(ds3dbuffer->flMaxDistance < 0.0f)
2188 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2189 return DSERR_INVALIDPARAM;
2192 if(ds3dbuffer->flMinDistance < 0.0f)
2194 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2195 return DSERR_INVALIDPARAM;
2198 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2199 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2200 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2202 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2203 return DSERR_INVALIDPARAM;
2206 if(apply == DS3D_DEFERRED)
2208 EnterCriticalSection(This->crst);
2209 This->params = *ds3dbuffer;
2210 This->params.dwSize = sizeof(This->params);
2211 This->dirty.bit.pos = 1;
2212 This->dirty.bit.vel = 1;
2213 This->dirty.bit.cone_angles = 1;
2214 This->dirty.bit.cone_orient = 1;
2215 This->dirty.bit.cone_outsidevolume = 1;
2216 This->dirty.bit.min_distance = 1;
2217 This->dirty.bit.max_distance = 1;
2218 This->dirty.bit.mode = 1;
2219 LeaveCriticalSection(This->crst);
2221 else
2223 union BufferParamFlags dirty = { 0 };
2224 dirty.bit.pos = 1;
2225 dirty.bit.vel = 1;
2226 dirty.bit.cone_angles = 1;
2227 dirty.bit.cone_orient = 1;
2228 dirty.bit.cone_outsidevolume = 1;
2229 dirty.bit.min_distance = 1;
2230 dirty.bit.max_distance = 1;
2231 dirty.bit.mode = 1;
2233 EnterCriticalSection(This->crst);
2234 setALContext(This->ctx);
2235 DS8Buffer_SetParams(This, ds3dbuffer, NULL, dirty.flags);
2236 checkALError();
2237 popALContext();
2238 LeaveCriticalSection(This->crst);
2241 return S_OK;
2244 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2246 DS8Buffer3D_QueryInterface,
2247 DS8Buffer3D_AddRef,
2248 DS8Buffer3D_Release,
2249 DS8Buffer3D_GetAllParameters,
2250 DS8Buffer3D_GetConeAngles,
2251 DS8Buffer3D_GetConeOrientation,
2252 DS8Buffer3D_GetConeOutsideVolume,
2253 DS8Buffer3D_GetMaxDistance,
2254 DS8Buffer3D_GetMinDistance,
2255 DS8Buffer3D_GetMode,
2256 DS8Buffer3D_GetPosition,
2257 DS8Buffer3D_GetVelocity,
2258 DS8Buffer3D_SetAllParameters,
2259 DS8Buffer3D_SetConeAngles,
2260 DS8Buffer3D_SetConeOrientation,
2261 DS8Buffer3D_SetConeOutsideVolume,
2262 DS8Buffer3D_SetMaxDistance,
2263 DS8Buffer3D_SetMinDistance,
2264 DS8Buffer3D_SetMode,
2265 DS8Buffer3D_SetPosition,
2266 DS8Buffer3D_SetVelocity
2270 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2272 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2273 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2276 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2278 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2279 LONG ret;
2281 InterlockedIncrement(&This->all_ref);
2282 ret = InterlockedIncrement(&This->not_ref);
2283 TRACE("new refcount %ld\n", ret);
2285 return ret;
2288 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2290 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2291 LONG ret;
2293 ret = InterlockedDecrement(&This->not_ref);
2294 TRACE("new refcount %ld\n", ret);
2295 if(InterlockedDecrement(&This->all_ref) == 0)
2296 DS8Buffer_Destroy(This);
2298 return ret;
2301 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2303 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2304 DSBPOSITIONNOTIFY *nots;
2305 DWORD state;
2306 HRESULT hr;
2308 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2310 EnterCriticalSection(This->crst);
2311 hr = DSERR_INVALIDPARAM;
2312 if(count && !notifications)
2313 goto out;
2315 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2316 if(FAILED(hr)) goto out;
2318 hr = DSERR_INVALIDCALL;
2319 if((state&DSBSTATUS_PLAYING))
2320 goto out;
2322 if(!count)
2324 HeapFree(GetProcessHeap(), 0, This->notify);
2325 This->notify = 0;
2326 This->nnotify = 0;
2327 hr = S_OK;
2329 else
2331 DWORD i;
2333 hr = DSERR_INVALIDPARAM;
2334 for(i = 0;i < count;++i)
2336 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2337 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2338 goto out;
2341 hr = E_OUTOFMEMORY;
2342 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2343 if(!nots) goto out;
2344 memcpy(nots, notifications, count*sizeof(*nots));
2346 HeapFree(GetProcessHeap(), 0, This->notify);
2347 This->notify = nots;
2348 This->nnotify = count;
2350 hr = S_OK;
2353 out:
2354 LeaveCriticalSection(This->crst);
2355 return hr;
2358 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2360 DS8BufferNot_QueryInterface,
2361 DS8BufferNot_AddRef,
2362 DS8BufferNot_Release,
2363 DS8BufferNot_SetNotificationPositions
2367 static void ApplyReverbParams(DS8Primary *prim, const EAXLISTENERPROPERTIES *props)
2369 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
2370 prim->eax_prop = *props;
2371 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DENSITY,
2372 clampF(powf(props->flEnvironmentSize, 3.0f) / 16.0f, 0.0f, 1.0f)
2374 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
2375 props->flEnvironmentDiffusion);
2377 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2378 mB_to_gain(props->lRoom));
2379 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2380 mB_to_gain(props->lRoomHF));
2382 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2383 props->flRoomRolloffFactor);
2385 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_TIME,
2386 props->flDecayTime);
2387 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
2388 props->flDecayHFRatio);
2390 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
2391 mB_to_gain(props->lReflections));
2392 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
2393 props->flReflectionsDelay);
2395 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
2396 mB_to_gain(props->lReverb));
2397 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
2398 props->flReverbDelay);
2400 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2401 mBF_to_gain(props->flAirAbsorptionHF));
2403 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2404 (props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2405 AL_TRUE : AL_FALSE);
2407 checkALError();
2409 prim->dirty.bit.effect = 1;
2412 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2414 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2415 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2418 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2420 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2421 LONG ret;
2423 InterlockedIncrement(&This->all_ref);
2424 ret = InterlockedIncrement(&This->prop_ref);
2425 TRACE("new refcount %ld\n", ret);
2427 return ret;
2430 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2432 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2433 LONG ret;
2435 ret = InterlockedDecrement(&This->prop_ref);
2436 TRACE("new refcount %ld\n", ret);
2437 if(InterlockedDecrement(&This->all_ref) == 0)
2438 DS8Buffer_Destroy(This);
2440 return ret;
2443 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2444 handled through secondary buffers. */
2445 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2446 REFGUID guidPropSet, ULONG dwPropID,
2447 LPVOID pInstanceData, ULONG cbInstanceData,
2448 LPVOID pPropData, ULONG cbPropData,
2449 ULONG *pcbReturned)
2451 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2452 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2454 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2455 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2457 if(!pcbReturned)
2458 return E_POINTER;
2459 *pcbReturned = 0;
2461 #define GET_PROP(hr, retsize, dst, dstsize, src, Type) do { \
2462 if(cbPropData >= sizeof(Type)) \
2464 union { \
2465 void *v; \
2466 Type *props; \
2467 } data = { dst }; \
2469 *data.props = src; \
2470 *(retsize) = sizeof(Type); \
2471 *(hr) = DS_OK; \
2473 } while(0)
2474 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2476 EnterCriticalSection(This->crst);
2478 hr = DSERR_INVALIDPARAM;
2479 if(This->filter[0] == 0)
2480 hr = E_PROP_ID_UNSUPPORTED;
2481 else switch(dwPropID)
2483 case DSPROPERTY_EAXBUFFER_ALLPARAMETERS:
2484 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop,
2485 EAX20BUFFERPROPERTIES);
2486 break;
2488 case DSPROPERTY_EAXBUFFER_DIRECT:
2489 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lDirect,
2490 LONG);
2491 break;
2492 case DSPROPERTY_EAXBUFFER_DIRECTHF:
2493 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lDirectHF,
2494 LONG);
2495 break;
2497 case DSPROPERTY_EAXBUFFER_ROOM:
2498 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lRoom,
2499 LONG);
2500 break;
2501 case DSPROPERTY_EAXBUFFER_ROOMHF:
2502 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lRoomHF,
2503 LONG);
2504 break;
2506 case DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR:
2507 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flRoomRolloffFactor,
2508 FLOAT);
2509 break;
2511 case DSPROPERTY_EAXBUFFER_OBSTRUCTION:
2512 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lObstruction,
2513 LONG);
2514 break;
2515 case DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO:
2516 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flObstructionLFRatio,
2517 FLOAT);
2518 break;
2520 case DSPROPERTY_EAXBUFFER_OCCLUSION:
2521 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lOcclusion,
2522 LONG);
2523 break;
2524 case DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO:
2525 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flOcclusionLFRatio,
2526 FLOAT);
2527 break;
2528 case DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO:
2529 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flOcclusionRoomRatio,
2530 FLOAT);
2531 break;
2533 case DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF:
2534 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.lOutsideVolumeHF,
2535 LONG);
2536 break;
2538 case DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR:
2539 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.flAirAbsorptionFactor,
2540 FLOAT);
2541 break;
2543 case DSPROPERTY_EAXBUFFER_FLAGS:
2544 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, This->eax_prop.dwFlags,
2545 DWORD);
2546 break;
2548 default:
2549 hr = E_PROP_ID_UNSUPPORTED;
2550 FIXME("Unhandled buffer propid: 0x%08lx\n", dwPropID);
2551 break;
2554 LeaveCriticalSection(This->crst);
2556 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2558 DS8Primary *prim = This->primary;
2560 EnterCriticalSection(This->crst);
2562 hr = DSERR_INVALIDPARAM;
2563 if(prim->effect == 0)
2564 hr = E_PROP_ID_UNSUPPORTED;
2565 else switch(dwPropID)
2567 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2568 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, prim->eax_prop,
2569 EAXLISTENERPROPERTIES);
2570 break;
2572 case DSPROPERTY_EAXLISTENER_ROOM:
2573 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2574 prim->eax_prop.lRoom, LONG);
2575 break;
2576 case DSPROPERTY_EAXLISTENER_ROOMHF:
2577 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2578 prim->eax_prop.lRoomHF, LONG);
2579 break;
2581 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2582 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2583 prim->eax_prop.flRoomRolloffFactor, FLOAT);
2584 break;
2586 case DSPROPERTY_EAXLISTENER_DECAYTIME:
2587 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2588 prim->eax_prop.flDecayTime, FLOAT);
2589 break;
2590 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
2591 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2592 prim->eax_prop.flDecayHFRatio, FLOAT);
2593 break;
2595 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
2596 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2597 prim->eax_prop.lReflections, LONG);
2598 break;
2599 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
2600 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2601 prim->eax_prop.flReflectionsDelay, FLOAT);
2602 break;
2604 case DSPROPERTY_EAXLISTENER_REVERB:
2605 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2606 prim->eax_prop.lReverb, LONG);
2607 break;
2608 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
2609 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2610 prim->eax_prop.flReverbDelay, FLOAT);
2611 break;
2613 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2614 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2615 prim->eax_prop.dwEnvironment, DWORD);
2616 break;
2618 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2619 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2620 prim->eax_prop.flEnvironmentSize, FLOAT);
2621 break;
2622 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2623 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2624 prim->eax_prop.flEnvironmentDiffusion, FLOAT);
2625 break;
2627 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2628 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2629 prim->eax_prop.flAirAbsorptionHF, FLOAT);
2630 break;
2632 case DSPROPERTY_EAXLISTENER_FLAGS:
2633 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2634 prim->eax_prop.dwFlags, DWORD);
2635 break;
2637 default:
2638 hr = E_PROP_ID_UNSUPPORTED;
2639 FIXME("Unhandled listener propid: 0x%08lx\n", dwPropID);
2640 break;
2643 LeaveCriticalSection(This->crst);
2645 else
2646 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2647 #undef GET_PROP
2649 return hr;
2652 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2653 REFGUID guidPropSet, ULONG dwPropID,
2654 LPVOID pInstanceData, ULONG cbInstanceData,
2655 LPVOID pPropData, ULONG cbPropData)
2657 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2658 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2660 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2661 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2663 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2665 DWORD propid = dwPropID & ~DSPROPERTY_EAXBUFFER_DEFERRED;
2666 BOOL immediate = !(dwPropID&DSPROPERTY_EAXBUFFER_DEFERRED);
2668 EnterCriticalSection(This->crst);
2669 setALContext(This->ctx);
2671 hr = DSERR_INVALIDPARAM;
2672 if(This->filter[0] == 0)
2673 hr = E_PROP_ID_UNSUPPORTED;
2674 else switch(propid)
2676 case DSPROPERTY_EAXBUFFER_NONE: /* not setting any property, just applying */
2677 hr = DS_OK;
2678 break;
2680 case DSPROPERTY_EAXBUFFER_ALLPARAMETERS:
2681 if(cbPropData >= sizeof(EAX20BUFFERPROPERTIES))
2683 union {
2684 const void *v;
2685 const EAX20BUFFERPROPERTIES *props;
2686 } data = { pPropData };
2688 This->eax_prop = *data.props;
2689 /* TODO: Apply filter props */
2691 This->dirty.bit.dry_filter = 1;
2692 This->dirty.bit.wet_filter = 1;
2693 This->dirty.bit.room_rolloff = 1;
2694 This->dirty.bit.out_cone_vol = 1;
2695 This->dirty.bit.air_absorb = 1;
2696 This->dirty.bit.flags = 1;
2697 hr = DS_OK;
2699 break;
2701 case DSPROPERTY_EAXBUFFER_DIRECT:
2702 if(cbPropData >= sizeof(LONG))
2704 union {
2705 const void *v;
2706 const LONG *props;
2707 } data = { pPropData };
2709 This->eax_prop.lDirect = *data.props;
2710 /* TODO: Apply filter props */
2712 This->dirty.bit.dry_filter = 1;
2713 hr = DS_OK;
2715 break;
2716 case DSPROPERTY_EAXBUFFER_DIRECTHF:
2717 if(cbPropData >= sizeof(LONG))
2719 union {
2720 const void *v;
2721 const LONG *props;
2722 } data = { pPropData };
2724 This->eax_prop.lDirectHF = *data.props;
2725 /* TODO: Apply filter props */
2727 This->dirty.bit.dry_filter = 1;
2728 hr = DS_OK;
2730 break;
2732 case DSPROPERTY_EAXBUFFER_ROOM:
2733 if(cbPropData >= sizeof(LONG))
2735 union {
2736 const void *v;
2737 const LONG *props;
2738 } data = { pPropData };
2740 This->eax_prop.lRoom = *data.props;
2741 /* TODO: Apply filter props */
2743 This->dirty.bit.wet_filter = 1;
2744 hr = DS_OK;
2746 break;
2747 case DSPROPERTY_EAXBUFFER_ROOMHF:
2748 if(cbPropData >= sizeof(LONG))
2750 union {
2751 const void *v;
2752 const LONG *props;
2753 } data = { pPropData };
2755 This->eax_prop.lRoomHF = *data.props;
2756 /* TODO: Apply filter props */
2758 This->dirty.bit.wet_filter = 1;
2759 hr = DS_OK;
2761 break;
2763 case DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR:
2764 if(cbPropData >= sizeof(FLOAT))
2766 union {
2767 const void *v;
2768 const FLOAT *props;
2769 } data = { pPropData };
2771 This->eax_prop.flRoomRolloffFactor = *data.props;
2773 This->dirty.bit.room_rolloff = 1;
2774 hr = DS_OK;
2776 break;
2778 case DSPROPERTY_EAXBUFFER_OBSTRUCTION:
2779 if(cbPropData >= sizeof(LONG))
2781 union {
2782 const void *v;
2783 const LONG *props;
2784 } data = { pPropData };
2786 This->eax_prop.lObstruction = *data.props;
2787 /* TODO: Apply filter props */
2789 This->dirty.bit.dry_filter = 1;
2790 hr = DS_OK;
2792 break;
2793 case DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO:
2794 if(cbPropData >= sizeof(FLOAT))
2796 union {
2797 const void *v;
2798 const FLOAT *props;
2799 } data = { pPropData };
2801 This->eax_prop.flObstructionLFRatio = *data.props;
2802 /* TODO: Apply filter props */
2804 This->dirty.bit.dry_filter = 1;
2805 hr = DS_OK;
2807 break;
2809 case DSPROPERTY_EAXBUFFER_OCCLUSION:
2810 if(cbPropData >= sizeof(LONG))
2812 union {
2813 const void *v;
2814 const LONG *props;
2815 } data = { pPropData };
2817 This->eax_prop.lOcclusion = *data.props;
2818 /* TODO: Apply filter props */
2820 This->dirty.bit.dry_filter = 1;
2821 This->dirty.bit.wet_filter = 1;
2822 hr = DS_OK;
2824 break;
2825 case DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO:
2826 if(cbPropData >= sizeof(FLOAT))
2828 union {
2829 const void *v;
2830 const FLOAT *props;
2831 } data = { pPropData };
2833 This->eax_prop.flOcclusionLFRatio = *data.props;
2834 /* TODO: Apply filter props */
2836 This->dirty.bit.dry_filter = 1;
2837 This->dirty.bit.wet_filter = 1;
2838 hr = DS_OK;
2840 break;
2841 case DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO:
2842 if(cbPropData >= sizeof(FLOAT))
2844 union {
2845 const void *v;
2846 const FLOAT *props;
2847 } data = { pPropData };
2849 This->eax_prop.flOcclusionRoomRatio = *data.props;
2850 /* TODO: Apply filter props */
2852 This->dirty.bit.dry_filter = 1;
2853 This->dirty.bit.wet_filter = 1;
2854 hr = DS_OK;
2856 break;
2858 case DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF:
2859 if(cbPropData >= sizeof(LONG))
2861 union {
2862 const void *v;
2863 const LONG *props;
2864 } data = { pPropData };
2866 This->eax_prop.lOutsideVolumeHF = *data.props;
2868 This->dirty.bit.out_cone_vol = 1;
2869 hr = DS_OK;
2871 break;
2873 case DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR:
2874 if(cbPropData >= sizeof(FLOAT))
2876 union {
2877 const void *v;
2878 const FLOAT *props;
2879 } data = { pPropData };
2881 This->eax_prop.flAirAbsorptionFactor = *data.props;
2883 This->dirty.bit.air_absorb = 1;
2884 hr = DS_OK;
2886 break;
2888 case DSPROPERTY_EAXBUFFER_FLAGS:
2889 if(cbPropData >= sizeof(DWORD))
2891 union {
2892 const void *v;
2893 const DWORD *props;
2894 } data = { pPropData };
2896 This->eax_prop.dwFlags = *data.props;
2898 This->dirty.bit.flags = 1;
2899 hr = DS_OK;
2901 break;
2903 default:
2904 hr = E_PROP_ID_UNSUPPORTED;
2905 FIXME("Unhandled buffer propid: 0x%08lx\n", propid);
2906 break;
2909 if(hr == DS_OK && immediate)
2910 DS8Primary3D_CommitDeferredSettings(&This->primary->IDirectSound3DListener_iface);
2912 popALContext();
2913 LeaveCriticalSection(This->crst);
2915 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2917 DS8Primary *prim = This->primary;
2918 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
2919 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
2921 EnterCriticalSection(prim->crst);
2922 setALContext(prim->ctx);
2924 hr = DSERR_INVALIDPARAM;
2925 if(prim->effect == 0)
2926 hr = E_PROP_ID_UNSUPPORTED;
2927 else switch(propid)
2929 case DSPROPERTY_EAXLISTENER_NONE: /* not setting any property, just applying */
2930 hr = DS_OK;
2931 break;
2933 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2934 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
2936 union {
2937 const void *v;
2938 const EAXLISTENERPROPERTIES *props;
2939 } data = { pPropData };
2941 ApplyReverbParams(prim, data.props);
2942 hr = DS_OK;
2944 break;
2946 case DSPROPERTY_EAXLISTENER_ROOM:
2947 if(cbPropData >= sizeof(LONG))
2949 union {
2950 const void *v;
2951 const LONG *l;
2952 } data = { pPropData };
2954 prim->eax_prop.lRoom = *data.l;
2955 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2956 mB_to_gain(prim->eax_prop.lRoom));
2957 checkALError();
2959 prim->dirty.bit.effect = 1;
2960 hr = DS_OK;
2962 break;
2963 case DSPROPERTY_EAXLISTENER_ROOMHF:
2964 if(cbPropData >= sizeof(LONG))
2966 union {
2967 const void *v;
2968 const LONG *l;
2969 } data = { pPropData };
2971 prim->eax_prop.lRoomHF = *data.l;
2972 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2973 mB_to_gain(prim->eax_prop.lRoomHF));
2974 checkALError();
2976 prim->dirty.bit.effect = 1;
2977 hr = DS_OK;
2979 break;
2981 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2982 if(cbPropData >= sizeof(FLOAT))
2984 union {
2985 const void *v;
2986 const FLOAT *fl;
2987 } data = { pPropData };
2989 prim->eax_prop.flRoomRolloffFactor = *data.fl;
2990 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2991 prim->eax_prop.flRoomRolloffFactor);
2992 checkALError();
2994 prim->dirty.bit.effect = 1;
2995 hr = DS_OK;
2997 break;
2999 case DSPROPERTY_EAXLISTENER_DECAYTIME:
3000 if(cbPropData >= sizeof(FLOAT))
3002 union {
3003 const void *v;
3004 const FLOAT *fl;
3005 } data = { pPropData };
3007 prim->eax_prop.flDecayTime = *data.fl;
3008 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_TIME,
3009 prim->eax_prop.flDecayTime);
3010 checkALError();
3012 prim->dirty.bit.effect = 1;
3013 hr = DS_OK;
3015 break;
3016 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
3017 if(cbPropData >= sizeof(FLOAT))
3019 union {
3020 const void *v;
3021 const FLOAT *fl;
3022 } data = { pPropData };
3024 prim->eax_prop.flDecayHFRatio = *data.fl;
3025 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
3026 prim->eax_prop.flDecayHFRatio);
3027 checkALError();
3029 prim->dirty.bit.effect = 1;
3030 hr = DS_OK;
3032 break;
3034 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
3035 if(cbPropData >= sizeof(LONG))
3037 union {
3038 const void *v;
3039 const LONG *l;
3040 } data = { pPropData };
3042 prim->eax_prop.lReflections = *data.l;
3043 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
3044 mB_to_gain(prim->eax_prop.lReflections));
3045 checkALError();
3047 prim->dirty.bit.effect = 1;
3048 hr = DS_OK;
3050 break;
3051 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
3052 if(cbPropData >= sizeof(FLOAT))
3054 union {
3055 const void *v;
3056 const FLOAT *fl;
3057 } data = { pPropData };
3059 prim->eax_prop.flReflectionsDelay = *data.fl;
3060 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
3061 prim->eax_prop.flReflectionsDelay);
3062 checkALError();
3064 prim->dirty.bit.effect = 1;
3065 hr = DS_OK;
3067 break;
3069 case DSPROPERTY_EAXLISTENER_REVERB:
3070 if(cbPropData >= sizeof(LONG))
3072 union {
3073 const void *v;
3074 const LONG *l;
3075 } data = { pPropData };
3077 prim->eax_prop.lReverb = *data.l;
3078 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
3079 mB_to_gain(prim->eax_prop.lReverb));
3080 checkALError();
3082 prim->dirty.bit.effect = 1;
3083 hr = DS_OK;
3085 break;
3086 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
3087 if(cbPropData >= sizeof(FLOAT))
3089 union {
3090 const void *v;
3091 const FLOAT *fl;
3092 } data = { pPropData };
3094 prim->eax_prop.flReverbDelay = *data.fl;
3095 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
3096 prim->eax_prop.flReverbDelay);
3097 checkALError();
3099 prim->dirty.bit.effect = 1;
3100 hr = DS_OK;
3102 break;
3104 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
3105 if(cbPropData >= sizeof(DWORD))
3107 union {
3108 const void *v;
3109 const DWORD *dw;
3110 } data = { pPropData };
3112 if(*data.dw <= EAX_MAX_ENVIRONMENT)
3114 ApplyReverbParams(prim, &EnvironmentDefaults[*data.dw]);
3115 hr = DS_OK;
3118 break;
3120 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
3121 if(cbPropData >= sizeof(FLOAT))
3123 union {
3124 const void *v;
3125 const FLOAT *fl;
3126 } data = { pPropData };
3128 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
3130 float scale = (*data.fl)/prim->eax_prop.flEnvironmentSize;
3132 prim->eax_prop.flEnvironmentSize = *data.fl;
3134 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
3136 prim->eax_prop.flDecayTime *= scale;
3137 prim->eax_prop.flDecayTime = clampF(prim->eax_prop.flDecayTime, 0.1f, 20.0f);
3139 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
3141 prim->eax_prop.lReflections -= gain_to_mB(scale);
3142 prim->eax_prop.lReflections = clampI(prim->eax_prop.lReflections, -10000, 1000);
3144 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
3146 prim->eax_prop.flReflectionsDelay *= scale;
3147 prim->eax_prop.flReflectionsDelay = clampF(prim->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
3149 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
3151 prim->eax_prop.lReverb -= gain_to_mB(scale);
3152 prim->eax_prop.lReverb = clampI(prim->eax_prop.lReverb, -10000, 2000);
3154 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
3156 prim->eax_prop.flReverbDelay *= scale;
3157 prim->eax_prop.flReverbDelay = clampF(prim->eax_prop.flReverbDelay, 0.0f, 0.1f);
3160 ApplyReverbParams(prim, &prim->eax_prop);
3161 hr = DS_OK;
3164 break;
3165 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
3166 if(cbPropData >= sizeof(FLOAT))
3168 union {
3169 const void *v;
3170 const FLOAT *fl;
3171 } data = { pPropData };
3173 prim->eax_prop.flEnvironmentDiffusion = *data.fl;
3174 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
3175 prim->eax_prop.flEnvironmentDiffusion);
3176 checkALError();
3178 prim->dirty.bit.effect = 1;
3179 hr = DS_OK;
3181 break;
3183 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
3184 if(cbPropData >= sizeof(FLOAT))
3186 union {
3187 const void *v;
3188 const FLOAT *fl;
3189 } data = { pPropData };
3191 prim->eax_prop.flAirAbsorptionHF = *data.fl;
3192 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
3193 mBF_to_gain(prim->eax_prop.flAirAbsorptionHF));
3194 checkALError();
3196 prim->dirty.bit.effect = 1;
3197 hr = DS_OK;
3199 break;
3201 case DSPROPERTY_EAXLISTENER_FLAGS:
3202 if(cbPropData >= sizeof(DWORD))
3204 union {
3205 const void *v;
3206 const DWORD *dw;
3207 } data = { pPropData };
3209 prim->eax_prop.dwFlags = *data.dw;
3210 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
3211 (prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
3212 AL_TRUE : AL_FALSE);
3213 checkALError();
3215 prim->dirty.bit.effect = 1;
3216 hr = DS_OK;
3218 break;
3220 default:
3221 hr = E_PROP_ID_UNSUPPORTED;
3222 FIXME("Unhandled listener propid: 0x%08lx\n", propid);
3223 break;
3226 if(hr == DS_OK && immediate)
3227 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
3229 popALContext();
3230 LeaveCriticalSection(prim->crst);
3232 else
3233 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
3235 return hr;
3238 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
3239 REFGUID guidPropSet, ULONG dwPropID,
3240 ULONG *pTypeSupport)
3242 DS8Buffer *This = impl_from_IKsPropertySet(iface);
3243 HRESULT hr = E_PROP_ID_UNSUPPORTED;
3245 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
3247 if(!pTypeSupport)
3248 return E_POINTER;
3249 *pTypeSupport = 0;
3251 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
3253 EnterCriticalSection(This->crst);
3255 if(This->filter[0] == 0)
3256 hr = E_PROP_ID_UNSUPPORTED;
3257 else if(dwPropID == DSPROPERTY_EAXBUFFER_NONE)
3259 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
3260 hr = DS_OK;
3262 else if(dwPropID == DSPROPERTY_EAXBUFFER_ALLPARAMETERS ||
3263 dwPropID == DSPROPERTY_EAXBUFFER_DIRECT ||
3264 dwPropID == DSPROPERTY_EAXBUFFER_DIRECTHF ||
3265 dwPropID == DSPROPERTY_EAXBUFFER_ROOM ||
3266 dwPropID == DSPROPERTY_EAXBUFFER_ROOMHF ||
3267 dwPropID == DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR ||
3268 dwPropID == DSPROPERTY_EAXBUFFER_OBSTRUCTION ||
3269 dwPropID == DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO ||
3270 dwPropID == DSPROPERTY_EAXBUFFER_OCCLUSION ||
3271 dwPropID == DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO ||
3272 dwPropID == DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO ||
3273 dwPropID == DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF ||
3274 dwPropID == DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR ||
3275 dwPropID == DSPROPERTY_EAXBUFFER_FLAGS)
3277 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
3278 hr = DS_OK;
3280 else
3281 FIXME("Unhandled buffer propid: 0x%08lx\n", dwPropID);
3283 LeaveCriticalSection(This->crst);
3285 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
3287 DS8Primary *prim = This->primary;
3289 EnterCriticalSection(This->crst);
3291 if(prim->effect == 0)
3292 hr = E_PROP_ID_UNSUPPORTED;
3293 else if(dwPropID == DSPROPERTY_EAXLISTENER_NONE)
3295 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
3296 hr = DS_OK;
3298 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
3299 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
3300 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
3301 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
3302 dwPropID == DSPROPERTY_EAXLISTENER_DECAYTIME ||
3303 dwPropID == DSPROPERTY_EAXLISTENER_DECAYHFRATIO ||
3304 dwPropID == DSPROPERTY_EAXLISTENER_REFLECTIONS ||
3305 dwPropID == DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY ||
3306 dwPropID == DSPROPERTY_EAXLISTENER_REVERB ||
3307 dwPropID == DSPROPERTY_EAXLISTENER_REVERBDELAY ||
3308 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
3309 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
3310 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
3311 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
3312 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
3314 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
3315 hr = DS_OK;
3317 else
3318 FIXME("Unhandled listener propid: 0x%08lx\n", dwPropID);
3320 LeaveCriticalSection(This->crst);
3322 else
3323 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
3325 return hr;
3328 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
3330 DS8BufferProp_QueryInterface,
3331 DS8BufferProp_AddRef,
3332 DS8BufferProp_Release,
3333 DS8BufferProp_Get,
3334 DS8BufferProp_Set,
3335 DS8BufferProp_QuerySupport