Use a macro to condense code duplication
[dsound-openal.git] / buffer.c
blob9efb17d2330d4e9759f9bc0e35af42057ada8ac7
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);
551 if(This->buffer)
552 DS8Data_Release(This->buffer);
554 popALContext();
556 HeapFree(GetProcessHeap(), 0, This->notify);
558 for(i = 0;i < prim->NumBufferGroups;++i)
560 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
561 if(idx < 64)
563 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
564 This = NULL;
565 break;
568 LeaveCriticalSection(prim->crst);
572 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
574 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
576 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
578 *ppv = NULL;
579 if(IsEqualIID(riid, &IID_IUnknown))
580 *ppv = &This->IDirectSoundBuffer8_iface;
581 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
582 *ppv = &This->IDirectSoundBuffer8_iface;
583 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
585 if(This->primary->parent->is_8)
586 *ppv = &This->IDirectSoundBuffer8_iface;
588 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
590 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
591 *ppv = &This->IDirectSound3DBuffer_iface;
593 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
595 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
596 *ppv = &This->IDirectSoundNotify_iface;
598 else if(IsEqualIID(riid, &IID_IKsPropertySet))
599 *ppv = &This->IKsPropertySet_iface;
600 else
601 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
603 if(*ppv)
605 IUnknown_AddRef((IUnknown*)*ppv);
606 return S_OK;
609 return E_NOINTERFACE;
612 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
614 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
615 LONG ret;
617 InterlockedIncrement(&This->all_ref);
618 ret = InterlockedIncrement(&This->ref);
619 TRACE("new refcount %ld\n", ret);
621 return ret;
624 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
626 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
627 LONG ret;
629 ret = InterlockedDecrement(&This->ref);
630 TRACE("new refcount %ld\n", ret);
631 if(InterlockedDecrement(&This->all_ref) == 0)
632 DS8Buffer_Destroy(This);
634 return ret;
637 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
639 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
641 TRACE("(%p)->(%p)\n", iface, caps);
643 if(!caps || caps->dwSize < sizeof(*caps))
645 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
646 return DSERR_INVALIDPARAM;
649 caps->dwFlags = This->buffer->dsbflags;
650 caps->dwBufferBytes = This->buffer->buf_size;
651 caps->dwUnlockTransferRate = 4096;
652 caps->dwPlayCpuOverhead = 0;
653 return S_OK;
656 HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
658 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
659 ALsizei writecursor, pos;
660 DS8Data *data;
662 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
664 data = This->buffer;
665 if(This->segsize != 0)
667 ALint queued = QBUFFERS;
668 ALint status = 0;
669 ALint ofs = 0;
671 EnterCriticalSection(This->crst);
673 setALContext(This->ctx);
674 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
675 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
676 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
677 checkALError();
678 popALContext();
680 if(status == AL_STOPPED)
681 pos = This->segsize*queued + This->queue_base;
682 else
683 pos = ofs + This->queue_base;
684 if(pos >= data->buf_size)
686 if(This->islooping)
687 pos %= data->buf_size;
688 else if(This->isplaying)
690 pos = data->buf_size;
691 alSourceStop(This->source);
692 alSourcei(This->source, AL_BUFFER, 0);
693 This->curidx = 0;
694 This->isplaying = FALSE;
697 if(This->isplaying)
698 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
699 else
700 writecursor = pos % data->buf_size;
702 LeaveCriticalSection(This->crst);
704 else
706 const WAVEFORMATEX *format = &data->format.Format;
707 ALint status = 0;
708 ALint ofs = 0;
710 setALContext(This->ctx);
711 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
712 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
713 checkALError();
714 popALContext();
716 /* AL_STOPPED means the source naturally reached its end, where
717 * DirectSound's position should be at the end (OpenAL reports a 0
718 * position). The Stop method correlates to pausing, which would put
719 * the source into an AL_PAUSED state and hold its current position.
721 pos = (status == AL_STOPPED) ? data->buf_size : ofs;
722 if(status == AL_PLAYING)
724 writecursor = format->nSamplesPerSec / This->primary->refresh;
725 writecursor *= format->nBlockAlign;
727 else
728 writecursor = 0;
729 writecursor = (writecursor + pos) % data->buf_size;
731 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
733 if(pos > data->buf_size)
735 ERR("playpos > buf_size\n");
736 pos %= data->buf_size;
738 if(writecursor >= data->buf_size)
740 ERR("writepos >= buf_size\n");
741 writecursor %= data->buf_size;
744 if(playpos) *playpos = pos;
745 if(curpos) *curpos = writecursor;
747 return S_OK;
750 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
752 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
753 HRESULT hr = S_OK;
754 UINT size;
756 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
758 if(!wfx && !written)
760 WARN("Cannot report format or format size\n");
761 return DSERR_INVALIDPARAM;
764 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
765 if(wfx)
767 if(allocated < size)
768 hr = DSERR_INVALIDPARAM;
769 else
770 memcpy(wfx, &This->buffer->format.Format, size);
772 if(written)
773 *written = size;
775 return hr;
778 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
780 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
781 HRESULT hr;
783 TRACE("(%p)->(%p)\n", iface, vol);
785 if(!vol)
787 WARN("Invalid pointer\n");
788 return DSERR_INVALIDPARAM;
791 hr = DSERR_CONTROLUNAVAIL;
792 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
793 WARN("Volume control not set\n");
794 else
796 ALfloat gain = 1.0f;
798 setALContext(This->ctx);
799 alGetSourcef(This->source, AL_GAIN, &gain);
800 checkALError();
801 popALContext();
803 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
804 hr = DS_OK;
807 return hr;
810 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
812 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
813 HRESULT hr;
815 TRACE("(%p)->(%p)\n", iface, pan);
817 if(!pan)
819 WARN("Invalid pointer\n");
820 return DSERR_INVALIDPARAM;
823 hr = DSERR_CONTROLUNAVAIL;
824 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
825 WARN("Panning control not set\n");
826 else
828 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
829 *pan = 0;
830 else
832 ALfloat pos[3];
834 setALContext(This->ctx);
835 alGetSourcefv(This->source, AL_POSITION, pos);
836 checkALError();
837 popALContext();
839 *pan = clampI((LONG)((pos[0]+0.5f)*(DSBPAN_RIGHT-DSBPAN_LEFT) + 0.5f) + DSBPAN_LEFT,
840 DSBPAN_LEFT, DSBPAN_RIGHT);
842 hr = DS_OK;
845 return hr;
848 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
850 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
851 HRESULT hr;
853 TRACE("(%p)->(%p)\n", iface, freq);
855 if(!freq)
857 WARN("Invalid pointer\n");
858 return DSERR_INVALIDPARAM;
861 hr = DSERR_CONTROLUNAVAIL;
862 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
863 WARN("Frequency control not set\n");
864 else
866 ALfloat pitch = 1.0f;
868 setALContext(This->ctx);
869 alGetSourcefv(This->source, AL_PITCH, &pitch);
870 checkALError();
871 popALContext();
873 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
874 hr = DS_OK;
877 return hr;
880 HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
882 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
883 ALint state, looping;
885 TRACE("(%p)->(%p)\n", iface, status);
887 if(!status)
889 WARN("Invalid pointer\n");
890 return DSERR_INVALIDPARAM;
892 *status = 0;
894 if(This->segsize == 0)
896 setALContext(This->ctx);
897 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
898 alGetSourcei(This->source, AL_LOOPING, &looping);
899 checkALError();
900 popALContext();
902 else
904 EnterCriticalSection(This->crst);
905 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
906 looping = This->islooping;
907 LeaveCriticalSection(This->crst);
910 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
912 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
913 *status |= DSBSTATUS_LOCSOFTWARE;
914 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
915 *status |= DSBSTATUS_LOCHARDWARE;
917 if(state == AL_PLAYING)
918 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
920 TRACE("%p status = 0x%08lx\n", This, *status);
921 return S_OK;
924 HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
926 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
927 DS3DBUFFER *ds3dbuffer;
928 DS8Primary *prim;
929 DS8Data *data;
930 HRESULT hr;
932 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
934 EnterCriticalSection(This->crst);
935 setALContext(This->ctx);
937 hr = DSERR_ALREADYINITIALIZED;
938 if(This->source) goto out;
940 if(!This->buffer)
942 hr = DSERR_INVALIDPARAM;
943 if(!desc)
945 WARN("Missing DSound buffer description\n");
946 goto out;
948 if(!desc->lpwfxFormat)
950 WARN("Missing buffer format (%p)\n", This);
951 goto out;
953 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
955 if(This->primary->parent->is_8)
957 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
958 * buffers */
959 WARN("Can't create multi-channel 3D buffers\n");
960 goto out;
962 else
964 static int once = 0;
965 if(!once++)
966 ERR("Multi-channel 3D sounds are not spatialized\n");
969 if((desc->dwFlags&DSBCAPS_CTRLPAN) && desc->lpwfxFormat->nChannels != 1)
971 static int once = 0;
972 if(!once++)
973 ERR("Panning for multi-channel buffers is not supported\n");
976 hr = DS8Data_Create(&This->buffer, desc, This->primary);
977 if(FAILED(hr)) goto out;
979 data = This->buffer;
980 if(data->format.Format.wBitsPerSample == 8)
981 memset(data->data, 0x80, data->buf_size);
982 else
983 memset(data->data, 0x00, data->buf_size);
986 prim = This->primary;
987 data = This->buffer;
988 if(!(data->dsbflags&DSBCAPS_STATIC) && !prim->SupportedExt[SOFTX_MAP_BUFFER])
990 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
991 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
992 This->segsize += data->format.Format.nBlockAlign - 1;
993 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
995 alGenBuffers(QBUFFERS, This->stream_bids);
996 checkALError();
999 hr = DSERR_ALLOCATED;
1000 if(!prim->parent->share->nsources)
1001 goto out;
1003 This->source = prim->sources[--(prim->parent->share->nsources)];
1004 alSourceRewind(This->source);
1005 alSourcef(This->source, AL_GAIN, 1.0f);
1006 alSourcef(This->source, AL_PITCH, 1.0f);
1007 checkALError();
1009 ds3dbuffer = &This->params;
1010 ds3dbuffer->dwSize = sizeof(This->params);
1011 ds3dbuffer->vPosition.x = 0.0f;
1012 ds3dbuffer->vPosition.y = 0.0f;
1013 ds3dbuffer->vPosition.z = 0.0f;
1014 ds3dbuffer->vVelocity.x = 0.0f;
1015 ds3dbuffer->vVelocity.y = 0.0f;
1016 ds3dbuffer->vVelocity.z = 0.0f;
1017 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1018 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1019 ds3dbuffer->vConeOrientation.x = 0.0f;
1020 ds3dbuffer->vConeOrientation.y = 0.0f;
1021 ds3dbuffer->vConeOrientation.z = 1.0f;
1022 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1023 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1024 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1025 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1027 if((data->dsbflags&DSBCAPS_CTRL3D))
1029 union BufferParamFlags dirty = { 0 };
1031 if(prim->auxslot != 0)
1032 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, AL_FILTER_NULL);
1034 dirty.bit.pos = 1;
1035 dirty.bit.vel = 1;
1036 dirty.bit.cone_angles = 1;
1037 dirty.bit.cone_orient = 1;
1038 dirty.bit.cone_outsidevolume = 1;
1039 dirty.bit.min_distance = 1;
1040 dirty.bit.max_distance = 1;
1041 dirty.bit.mode = 1;
1042 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
1043 checkALError();
1045 else
1047 ALuint source = This->source;
1049 if(prim->auxslot != 0)
1051 /* Simple hack to make reverb affect non-3D sounds too */
1052 alSource3i(source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, AL_FILTER_NULL);
1053 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1056 /* Non-3D sources aren't distance attenuated */
1057 This->ds3dmode = DS3DMODE_DISABLE;
1058 alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
1059 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1060 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1061 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1062 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1063 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1064 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1065 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1066 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1067 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1068 checkALError();
1070 hr = S_OK;
1072 out:
1073 popALContext();
1074 LeaveCriticalSection(This->crst);
1076 return hr;
1079 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1081 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1082 DWORD remain;
1084 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1086 if(!ptr1 || !len1)
1088 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1089 return DSERR_INVALIDPARAM;
1092 *ptr1 = NULL;
1093 *len1 = 0;
1094 if(ptr2) *ptr2 = NULL;
1095 if(len2) *len2 = 0;
1097 if((flags&DSBLOCK_FROMWRITECURSOR))
1098 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1099 else if(ofs >= (DWORD)This->buffer->buf_size)
1101 WARN("Invalid ofs %lu\n", ofs);
1102 return DSERR_INVALIDPARAM;
1104 if((flags&DSBLOCK_ENTIREBUFFER))
1105 bytes = This->buffer->buf_size;
1106 else if(bytes > (DWORD)This->buffer->buf_size)
1108 WARN("Invalid size %lu\n", bytes);
1109 return DSERR_INVALIDPARAM;
1112 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1114 WARN("Already locked\n");
1115 return DSERR_INVALIDPARAM;
1118 *ptr1 = This->buffer->data + ofs;
1119 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1121 *len1 = This->buffer->buf_size - ofs;
1122 remain = bytes - *len1;
1124 else
1126 *len1 = bytes;
1127 remain = 0;
1130 if(ptr2 && len2 && remain)
1132 *ptr2 = This->buffer->data;
1133 *len2 = remain;
1136 return DS_OK;
1139 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1141 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1142 ALint state = AL_STOPPED;
1143 DS8Data *data;
1144 HRESULT hr;
1146 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1148 EnterCriticalSection(This->crst);
1149 setALContext(This->ctx);
1151 hr = DSERR_BUFFERLOST;
1152 if(This->bufferlost)
1154 WARN("Buffer %p lost\n", This);
1155 goto out;
1158 data = This->buffer;
1159 if((data->dsbflags&DSBCAPS_LOCDEFER))
1161 if(!(data->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1163 if(flags & DSBPLAY_LOCSOFTWARE)
1164 data->dsbflags |= DSBCAPS_LOCSOFTWARE;
1165 else
1166 data->dsbflags |= DSBCAPS_LOCHARDWARE;
1169 else if(prio)
1171 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1172 hr = DSERR_INVALIDPARAM;
1173 goto out;
1176 if(This->segsize != 0)
1178 This->islooping = !!(flags&DSBPLAY_LOOPING);
1179 if(This->isplaying) state = AL_PLAYING;
1181 else
1183 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1184 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1186 checkALError();
1188 hr = S_OK;
1189 if(state == AL_PLAYING)
1190 goto out;
1192 if(This->segsize == 0)
1194 if(state != AL_PAUSED)
1195 alSourcei(This->source, AL_BUFFER, data->bid);
1196 alSourcePlay(This->source);
1198 else
1200 alSourceRewind(This->source);
1201 alSourcei(This->source, AL_BUFFER, 0);
1202 This->queue_base = This->data_offset % data->buf_size;
1203 This->curidx = 0;
1205 if(alGetError() != AL_NO_ERROR)
1207 ERR("Couldn't start source\n");
1208 alSourcei(This->source, AL_BUFFER, 0);
1209 checkALError();
1210 hr = DSERR_GENERIC;
1211 goto out;
1213 This->isplaying = TRUE;
1214 This->playflags = flags;
1216 if(This->nnotify)
1217 DS8Buffer_addnotify(This);
1219 out:
1220 popALContext();
1221 LeaveCriticalSection(This->crst);
1222 return hr;
1225 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1227 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1228 DS8Data *data;
1230 TRACE("(%p)->(%lu)\n", iface, pos);
1232 data = This->buffer;
1233 if(pos >= (DWORD)data->buf_size)
1234 return DSERR_INVALIDPARAM;
1235 pos -= pos%data->format.Format.nBlockAlign;
1237 EnterCriticalSection(This->crst);
1239 if(This->segsize != 0)
1241 if(This->isplaying)
1243 setALContext(This->ctx);
1244 /* Perform a flush, so the next timer update will restart at the
1245 * proper position */
1246 alSourceRewind(This->source);
1247 alSourcei(This->source, AL_BUFFER, 0);
1248 checkALError();
1249 popALContext();
1251 This->queue_base = This->data_offset = pos;
1252 This->curidx = 0;
1254 else
1256 setALContext(This->ctx);
1257 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1258 popALContext();
1260 This->lastpos = pos;
1262 LeaveCriticalSection(This->crst);
1263 return DS_OK;
1266 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1268 /* This call only works on primary buffers */
1269 WARN("(%p)->(%p)\n", iface, wfx);
1270 return DSERR_INVALIDCALL;
1273 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1275 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1276 HRESULT hr = S_OK;
1278 TRACE("(%p)->(%ld)\n", iface, vol);
1280 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1282 WARN("Invalid volume (%ld)\n", vol);
1283 return DSERR_INVALIDPARAM;
1286 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1287 hr = DSERR_CONTROLUNAVAIL;
1288 if(SUCCEEDED(hr))
1290 ALfloat fvol = mB_to_gain(vol);
1291 setALContext(This->ctx);
1292 alSourcef(This->source, AL_GAIN, fvol);
1293 popALContext();
1296 return hr;
1299 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1301 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1302 HRESULT hr = S_OK;
1304 TRACE("(%p)->(%ld)\n", iface, pan);
1306 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1308 WARN("invalid parameter: pan = %ld\n", pan);
1309 return DSERR_INVALIDPARAM;
1312 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1313 hr = DSERR_CONTROLUNAVAIL;
1314 else
1316 if(!(This->buffer->dsbflags&DSBCAPS_CTRL3D))
1318 ALfloat pos[3];
1319 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1320 pos[1] = 0.0f;
1321 /* NOTE: Strict movement along the X plane can cause the sound to
1322 * jump between left and right sharply. Using a curved path helps
1323 * smooth it out.
1325 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1327 setALContext(This->ctx);
1328 alSourcefv(This->source, AL_POSITION, pos);
1329 checkALError();
1330 popALContext();
1334 return hr;
1337 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1339 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1340 HRESULT hr = S_OK;
1342 TRACE("(%p)->(%lu)\n", iface, freq);
1344 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1346 WARN("invalid parameter: freq = %lu\n", freq);
1347 return DSERR_INVALIDPARAM;
1350 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1351 hr = DSERR_CONTROLUNAVAIL;
1352 else
1354 ALfloat pitch = 1.0f;
1355 if(freq != DSBFREQUENCY_ORIGINAL)
1356 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1358 setALContext(This->ctx);
1359 alSourcef(This->source, AL_PITCH, pitch);
1360 checkALError();
1361 popALContext();
1364 return hr;
1367 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1369 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1371 TRACE("(%p)->()\n", iface);
1373 EnterCriticalSection(This->crst);
1374 setALContext(This->ctx);
1376 alSourcePause(This->source);
1377 checkALError();
1379 This->isplaying = FALSE;
1380 DS8Primary_triggernots(This->primary);
1382 popALContext();
1383 LeaveCriticalSection(This->crst);
1385 return S_OK;
1388 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1390 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1391 DS8Data *buf = This->buffer;
1392 DWORD bufsize = buf->buf_size;
1393 DWORD_PTR ofs1, ofs2;
1394 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1395 HRESULT hr;
1397 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1399 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1401 WARN("Not locked\n");
1402 return DSERR_INVALIDPARAM;
1405 hr = DSERR_INVALIDPARAM;
1406 /* Make sure offset is between boundary and boundary + bufsize */
1407 ofs1 = (DWORD_PTR)ptr1;
1408 ofs2 = (DWORD_PTR)ptr2;
1409 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1410 goto out;
1411 ofs1 -= boundary;
1412 ofs2 = 0;
1413 if(bufsize-ofs1 < len1 || len2 > ofs1)
1414 goto out;
1415 if(!ptr2)
1416 len2 = 0;
1418 hr = DS_OK;
1419 if(!len1 && !len2)
1420 goto out;
1422 if(This->primary->SupportedExt[SOFTX_MAP_BUFFER])
1424 setALContext(This->ctx);
1425 This->ExtAL->FlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1426 checkALError();
1427 popALContext();
1429 else if(This->segsize == 0)
1431 setALContext(This->ctx);
1432 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1433 buf->format.Format.nSamplesPerSec);
1434 checkALError();
1435 popALContext();
1438 out:
1439 if(hr != S_OK)
1440 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1441 return hr;
1444 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1446 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1447 HRESULT hr;
1449 TRACE("(%p)->()\n", iface);
1451 EnterCriticalSection(This->crst);
1452 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1453 iface == This->primary->write_emu)
1455 This->bufferlost = 0;
1456 hr = S_OK;
1458 else
1459 hr = DSERR_BUFFERLOST;
1460 LeaveCriticalSection(This->crst);
1462 return hr;
1465 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1467 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1468 ALenum state = AL_INITIAL;
1469 DS8Data *data;
1470 HRESULT hr;
1471 DWORD i;
1473 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1475 data = This->buffer;
1476 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1478 WARN("FX control not set\n");
1479 return DSERR_CONTROLUNAVAIL;
1482 if(data->locked)
1484 WARN("Buffer is locked\n");
1485 return DSERR_INVALIDCALL;
1488 EnterCriticalSection(This->crst);
1489 setALContext(This->ctx);
1491 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1492 checkALError();
1493 if(This->segsize != 0 && state != AL_PLAYING)
1494 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1495 if(state == AL_PLAYING)
1497 WARN("Buffer is playing\n");
1498 hr = DSERR_INVALIDCALL;
1499 goto done;
1502 hr = DSERR_INVALIDPARAM;
1503 if(fxcount == 0)
1505 if(desc || rescodes)
1507 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1508 goto done;
1511 /* No effects; we can handle that */
1512 hr = DS_OK;
1513 goto done;
1516 if(!desc || !rescodes)
1518 WARN("NULL desc and/or result pointer specified.\n");
1519 goto done;
1522 /* We don't (currently) handle DSound effects */
1523 for(i = 0;i < fxcount;++i)
1525 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1526 rescodes[i] = DSFXR_FAILED;
1528 hr = DS_INCOMPLETE;
1530 done:
1531 popALContext();
1532 LeaveCriticalSection(This->crst);
1534 return hr;
1537 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1539 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1541 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1543 /* effects aren't supported at the moment.. */
1544 if(fxcount != 0 || rescodes)
1546 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1547 return DSERR_INVALIDPARAM;
1550 EnterCriticalSection(This->crst);
1551 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1553 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1554 if((flags&DSBPLAY_LOCSOFTWARE))
1555 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1556 else
1557 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1559 LeaveCriticalSection(This->crst);
1561 return S_OK;
1564 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1566 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1567 return E_NOTIMPL;
1570 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1571 DS8Buffer_QueryInterface,
1572 DS8Buffer_AddRef,
1573 DS8Buffer_Release,
1574 DS8Buffer_GetCaps,
1575 DS8Buffer_GetCurrentPosition,
1576 DS8Buffer_GetFormat,
1577 DS8Buffer_GetVolume,
1578 DS8Buffer_GetPan,
1579 DS8Buffer_GetFrequency,
1580 DS8Buffer_GetStatus,
1581 DS8Buffer_Initialize,
1582 DS8Buffer_Lock,
1583 DS8Buffer_Play,
1584 DS8Buffer_SetCurrentPosition,
1585 DS8Buffer_SetFormat,
1586 DS8Buffer_SetVolume,
1587 DS8Buffer_SetPan,
1588 DS8Buffer_SetFrequency,
1589 DS8Buffer_Stop,
1590 DS8Buffer_Unlock,
1591 DS8Buffer_Restore,
1592 DS8Buffer_SetFX,
1593 DS8Buffer_AcquireResources,
1594 DS8Buffer_GetObjectInPath
1598 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, LONG flags)
1600 const ALuint source = This->source;
1601 union BufferParamFlags dirty = { flags };
1603 if(dirty.bit.pos)
1604 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1605 -params->vPosition.z);
1606 if(dirty.bit.vel)
1607 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1608 -params->vVelocity.z);
1609 if(dirty.bit.cone_angles)
1611 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1612 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1614 if(dirty.bit.cone_orient)
1615 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1616 params->vConeOrientation.y,
1617 -params->vConeOrientation.z);
1618 if(dirty.bit.cone_outsidevolume)
1619 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1620 if(dirty.bit.min_distance)
1621 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1622 if(dirty.bit.max_distance)
1623 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1624 if(dirty.bit.mode)
1626 This->ds3dmode = params->dwMode;
1627 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1628 AL_TRUE : AL_FALSE);
1629 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1630 0.0f : This->primary->rollofffactor);
1634 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1636 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1637 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1640 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1642 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1643 LONG ret;
1645 InterlockedIncrement(&This->all_ref);
1646 ret = InterlockedIncrement(&This->ds3d_ref);
1647 TRACE("new refcount %ld\n", ret);
1649 return ret;
1652 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1654 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1655 LONG ret;
1657 ret = InterlockedDecrement(&This->ds3d_ref);
1658 TRACE("new refcount %ld\n", ret);
1659 if(InterlockedDecrement(&This->all_ref) == 0)
1660 DS8Buffer_Destroy(This);
1662 return ret;
1665 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1667 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1668 ALint inangle, outangle;
1670 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1671 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1673 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1674 return DSERR_INVALIDPARAM;
1677 EnterCriticalSection(This->crst);
1678 setALContext(This->ctx);
1680 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1681 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1682 checkALError();
1684 popALContext();
1685 LeaveCriticalSection(This->crst);
1687 *pdwInsideConeAngle = inangle;
1688 *pdwOutsideConeAngle = outangle;
1689 return S_OK;
1692 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1694 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1695 ALfloat dir[3];
1697 TRACE("(%p)->(%p)\n", This, orient);
1698 if(!orient)
1700 WARN("Invalid pointer\n");
1701 return DSERR_INVALIDPARAM;
1704 setALContext(This->ctx);
1705 alGetSourcefv(This->source, AL_DIRECTION, dir);
1706 checkALError();
1707 popALContext();
1709 orient->x = dir[0];
1710 orient->y = dir[1];
1711 orient->z = -dir[2];
1712 return S_OK;
1715 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1717 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1718 ALfloat gain;
1720 TRACE("(%p)->(%p)\n", This, vol);
1721 if(!vol)
1723 WARN("Invalid pointer\n");
1724 return DSERR_INVALIDPARAM;
1727 setALContext(This->ctx);
1728 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1729 checkALError();
1730 popALContext();
1732 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1733 return S_OK;
1736 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1738 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1739 ALfloat dist;
1741 TRACE("(%p)->(%p)\n", This, maxdist);
1742 if(!maxdist)
1744 WARN("Invalid pointer\n");
1745 return DSERR_INVALIDPARAM;
1748 setALContext(This->ctx);
1749 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1750 checkALError();
1751 popALContext();
1753 *maxdist = dist;
1754 return S_OK;
1757 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1759 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1760 ALfloat dist;
1762 TRACE("(%p)->(%p)\n", This, mindist);
1763 if(!mindist)
1765 WARN("Invalid pointer\n");
1766 return DSERR_INVALIDPARAM;
1769 setALContext(This->ctx);
1770 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1771 checkALError();
1772 popALContext();
1774 *mindist = dist;
1775 return S_OK;
1778 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1780 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1782 TRACE("(%p)->(%p)\n", This, mode);
1783 if(!mode)
1785 WARN("Invalid pointer\n");
1786 return DSERR_INVALIDPARAM;
1789 EnterCriticalSection(This->crst);
1790 *mode = This->ds3dmode;
1791 LeaveCriticalSection(This->crst);
1793 return S_OK;
1796 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1798 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1799 ALfloat alpos[3];
1801 TRACE("(%p)->(%p)\n", This, pos);
1802 if(!pos)
1804 WARN("Invalid pointer\n");
1805 return DSERR_INVALIDPARAM;
1808 setALContext(This->ctx);
1809 alGetSourcefv(This->source, AL_POSITION, alpos);
1810 checkALError();
1811 popALContext();
1813 pos->x = alpos[0];
1814 pos->y = alpos[1];
1815 pos->z = -alpos[2];
1816 return S_OK;
1819 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1821 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1822 ALfloat alvel[3];
1824 TRACE("(%p)->(%p)\n", This, vel);
1825 if(!vel)
1827 WARN("Invalid pointer\n");
1828 return DSERR_INVALIDPARAM;
1831 setALContext(This->ctx);
1832 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1833 checkALError();
1834 popALContext();
1836 vel->x = alvel[0];
1837 vel->y = alvel[1];
1838 vel->z = -alvel[2];
1839 return S_OK;
1842 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1844 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1846 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1848 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1850 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1851 return DSERR_INVALIDPARAM;
1854 EnterCriticalSection(This->crst);
1855 setALContext(This->ctx);
1857 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1858 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1859 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1860 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1861 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1862 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1863 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
1864 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
1866 popALContext();
1867 LeaveCriticalSection(This->crst);
1869 return DS_OK;
1872 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
1874 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1876 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
1877 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
1878 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
1880 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
1881 return DSERR_INVALIDPARAM;
1884 EnterCriticalSection(This->crst);
1885 if(apply == DS3D_DEFERRED)
1887 This->params.dwInsideConeAngle = dwInsideConeAngle;
1888 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
1889 This->dirty.bit.cone_angles = 1;
1891 else
1893 setALContext(This->ctx);
1894 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
1895 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
1896 checkALError();
1897 popALContext();
1899 LeaveCriticalSection(This->crst);
1901 return S_OK;
1904 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1906 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1908 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
1910 if(apply == DS3D_DEFERRED)
1912 EnterCriticalSection(This->crst);
1913 This->params.vConeOrientation.x = x;
1914 This->params.vConeOrientation.y = y;
1915 This->params.vConeOrientation.z = z;
1916 This->dirty.bit.cone_orient = 1;
1917 LeaveCriticalSection(This->crst);
1919 else
1921 setALContext(This->ctx);
1922 alSource3f(This->source, AL_DIRECTION, x, y, -z);
1923 checkALError();
1924 popALContext();
1927 return S_OK;
1930 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
1932 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1934 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
1935 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
1937 WARN("Invalid volume (%ld)\n", vol);
1938 return DSERR_INVALIDPARAM;
1941 if(apply == DS3D_DEFERRED)
1943 EnterCriticalSection(This->crst);
1944 This->params.lConeOutsideVolume = vol;
1945 This->dirty.bit.cone_outsidevolume = 1;
1946 LeaveCriticalSection(This->crst);
1948 else
1950 setALContext(This->ctx);
1951 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
1952 checkALError();
1953 popALContext();
1956 return S_OK;
1959 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
1961 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1963 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
1964 if(maxdist < 0.0f)
1966 WARN("Invalid max distance (%f)\n", maxdist);
1967 return DSERR_INVALIDPARAM;
1970 if(apply == DS3D_DEFERRED)
1972 EnterCriticalSection(This->crst);
1973 This->params.flMaxDistance = maxdist;
1974 This->dirty.bit.max_distance = 1;
1975 LeaveCriticalSection(This->crst);
1977 else
1979 setALContext(This->ctx);
1980 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
1981 checkALError();
1982 popALContext();
1985 return S_OK;
1988 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
1990 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1992 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
1993 if(mindist < 0.0f)
1995 WARN("Invalid min distance (%f)\n", mindist);
1996 return DSERR_INVALIDPARAM;
1999 if(apply == DS3D_DEFERRED)
2001 EnterCriticalSection(This->crst);
2002 This->params.flMinDistance = mindist;
2003 This->dirty.bit.min_distance = 1;
2004 LeaveCriticalSection(This->crst);
2006 else
2008 setALContext(This->ctx);
2009 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2010 checkALError();
2011 popALContext();
2014 return S_OK;
2017 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2019 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2021 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2022 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2023 mode != DS3DMODE_DISABLE)
2025 WARN("Invalid mode (%lu)\n", mode);
2026 return DSERR_INVALIDPARAM;
2029 EnterCriticalSection(This->crst);
2030 if(apply == DS3D_DEFERRED)
2032 This->params.dwMode = mode;
2033 This->dirty.bit.mode = 1;
2035 else
2037 setALContext(This->ctx);
2038 alSourcei(This->source, AL_SOURCE_RELATIVE,
2039 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2040 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2041 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2042 This->ds3dmode = mode;
2043 checkALError();
2044 popALContext();
2046 LeaveCriticalSection(This->crst);
2048 return S_OK;
2051 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2053 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2055 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2057 if(apply == DS3D_DEFERRED)
2059 EnterCriticalSection(This->crst);
2060 This->params.vPosition.x = x;
2061 This->params.vPosition.y = y;
2062 This->params.vPosition.z = z;
2063 This->dirty.bit.pos = 1;
2064 LeaveCriticalSection(This->crst);
2066 else
2068 setALContext(This->ctx);
2069 alSource3f(This->source, AL_POSITION, x, y, -z);
2070 checkALError();
2071 popALContext();
2074 return S_OK;
2077 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2079 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2081 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2083 if(apply == DS3D_DEFERRED)
2085 EnterCriticalSection(This->crst);
2086 This->params.vVelocity.x = x;
2087 This->params.vVelocity.y = y;
2088 This->params.vVelocity.z = z;
2089 This->dirty.bit.vel = 1;
2090 LeaveCriticalSection(This->crst);
2092 else
2094 setALContext(This->ctx);
2095 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2096 checkALError();
2097 popALContext();
2100 return S_OK;
2103 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2105 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2106 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2108 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2110 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2111 return DSERR_INVALIDPARAM;
2114 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2115 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2117 WARN("Invalid cone angles (%lu, %lu)\n",
2118 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2119 return DSERR_INVALIDPARAM;
2122 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2123 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2125 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2126 return DSERR_INVALIDPARAM;
2129 if(ds3dbuffer->flMaxDistance < 0.0f)
2131 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2132 return DSERR_INVALIDPARAM;
2135 if(ds3dbuffer->flMinDistance < 0.0f)
2137 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2138 return DSERR_INVALIDPARAM;
2141 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2142 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2143 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2145 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2146 return DSERR_INVALIDPARAM;
2149 if(apply == DS3D_DEFERRED)
2151 EnterCriticalSection(This->crst);
2152 This->params = *ds3dbuffer;
2153 This->params.dwSize = sizeof(This->params);
2154 This->dirty.bit.pos = 1;
2155 This->dirty.bit.vel = 1;
2156 This->dirty.bit.cone_angles = 1;
2157 This->dirty.bit.cone_orient = 1;
2158 This->dirty.bit.cone_outsidevolume = 1;
2159 This->dirty.bit.min_distance = 1;
2160 This->dirty.bit.max_distance = 1;
2161 This->dirty.bit.mode = 1;
2162 LeaveCriticalSection(This->crst);
2164 else
2166 union BufferParamFlags dirty = { 0 };
2167 dirty.bit.pos = 1;
2168 dirty.bit.vel = 1;
2169 dirty.bit.cone_angles = 1;
2170 dirty.bit.cone_orient = 1;
2171 dirty.bit.cone_outsidevolume = 1;
2172 dirty.bit.min_distance = 1;
2173 dirty.bit.max_distance = 1;
2174 dirty.bit.mode = 1;
2176 EnterCriticalSection(This->crst);
2177 setALContext(This->ctx);
2178 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
2179 checkALError();
2180 popALContext();
2181 LeaveCriticalSection(This->crst);
2184 return S_OK;
2187 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2189 DS8Buffer3D_QueryInterface,
2190 DS8Buffer3D_AddRef,
2191 DS8Buffer3D_Release,
2192 DS8Buffer3D_GetAllParameters,
2193 DS8Buffer3D_GetConeAngles,
2194 DS8Buffer3D_GetConeOrientation,
2195 DS8Buffer3D_GetConeOutsideVolume,
2196 DS8Buffer3D_GetMaxDistance,
2197 DS8Buffer3D_GetMinDistance,
2198 DS8Buffer3D_GetMode,
2199 DS8Buffer3D_GetPosition,
2200 DS8Buffer3D_GetVelocity,
2201 DS8Buffer3D_SetAllParameters,
2202 DS8Buffer3D_SetConeAngles,
2203 DS8Buffer3D_SetConeOrientation,
2204 DS8Buffer3D_SetConeOutsideVolume,
2205 DS8Buffer3D_SetMaxDistance,
2206 DS8Buffer3D_SetMinDistance,
2207 DS8Buffer3D_SetMode,
2208 DS8Buffer3D_SetPosition,
2209 DS8Buffer3D_SetVelocity
2213 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2215 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2216 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2219 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2221 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2222 LONG ret;
2224 InterlockedIncrement(&This->all_ref);
2225 ret = InterlockedIncrement(&This->not_ref);
2226 TRACE("new refcount %ld\n", ret);
2228 return ret;
2231 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2233 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2234 LONG ret;
2236 ret = InterlockedDecrement(&This->not_ref);
2237 TRACE("new refcount %ld\n", ret);
2238 if(InterlockedDecrement(&This->all_ref) == 0)
2239 DS8Buffer_Destroy(This);
2241 return ret;
2244 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2246 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2247 DSBPOSITIONNOTIFY *nots;
2248 DWORD state;
2249 HRESULT hr;
2251 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2253 EnterCriticalSection(This->crst);
2254 hr = DSERR_INVALIDPARAM;
2255 if(count && !notifications)
2256 goto out;
2258 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2259 if(FAILED(hr)) goto out;
2261 hr = DSERR_INVALIDCALL;
2262 if((state&DSBSTATUS_PLAYING))
2263 goto out;
2265 if(!count)
2267 HeapFree(GetProcessHeap(), 0, This->notify);
2268 This->notify = 0;
2269 This->nnotify = 0;
2270 hr = S_OK;
2272 else
2274 DWORD i;
2276 hr = DSERR_INVALIDPARAM;
2277 for(i = 0;i < count;++i)
2279 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2280 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2281 goto out;
2284 hr = E_OUTOFMEMORY;
2285 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2286 if(!nots) goto out;
2287 memcpy(nots, notifications, count*sizeof(*nots));
2289 HeapFree(GetProcessHeap(), 0, This->notify);
2290 This->notify = nots;
2291 This->nnotify = count;
2293 hr = S_OK;
2296 out:
2297 LeaveCriticalSection(This->crst);
2298 return hr;
2301 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2303 DS8BufferNot_QueryInterface,
2304 DS8BufferNot_AddRef,
2305 DS8BufferNot_Release,
2306 DS8BufferNot_SetNotificationPositions
2310 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2312 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2313 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2316 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2318 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2319 LONG ret;
2321 InterlockedIncrement(&This->all_ref);
2322 ret = InterlockedIncrement(&This->prop_ref);
2323 TRACE("new refcount %ld\n", ret);
2325 return ret;
2328 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2330 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2331 LONG ret;
2333 ret = InterlockedDecrement(&This->prop_ref);
2334 TRACE("new refcount %ld\n", ret);
2335 if(InterlockedDecrement(&This->all_ref) == 0)
2336 DS8Buffer_Destroy(This);
2338 return ret;
2341 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2342 handled through secondary buffers. */
2343 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2344 REFGUID guidPropSet, ULONG dwPropID,
2345 LPVOID pInstanceData, ULONG cbInstanceData,
2346 LPVOID pPropData, ULONG cbPropData,
2347 ULONG *pcbReturned)
2349 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2350 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2352 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2353 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2355 if(!pcbReturned)
2356 return E_POINTER;
2357 *pcbReturned = 0;
2359 #define GET_PROP(hr, retsize, dst, dstsize, src, Type) do { \
2360 if(cbPropData >= sizeof(Type)) \
2362 union { \
2363 void *v; \
2364 Type *props; \
2365 } data = { dst }; \
2367 *data.props = src; \
2368 *(retsize) = sizeof(Type); \
2369 *(hr) = DS_OK; \
2371 } while(0)
2372 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2374 FIXME("Unhandled propset: DSPROPSETID_EAX20_BufferProperties\n");
2376 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2378 DS8Primary *prim = This->primary;
2380 EnterCriticalSection(This->crst);
2382 hr = DSERR_INVALIDPARAM;
2383 if(prim->effect == 0)
2384 hr = E_PROP_ID_UNSUPPORTED;
2385 else switch(dwPropID)
2387 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2388 GET_PROP(&hr, pcbReturned, pPropData, cbPropData, prim->eax_prop,
2389 EAXLISTENERPROPERTIES);
2390 break;
2392 case DSPROPERTY_EAXLISTENER_ROOM:
2393 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2394 prim->eax_prop.lRoom, LONG);
2395 break;
2396 case DSPROPERTY_EAXLISTENER_ROOMHF:
2397 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2398 prim->eax_prop.lRoomHF, LONG);
2399 break;
2401 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2402 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2403 prim->eax_prop.flRoomRolloffFactor, FLOAT);
2404 break;
2406 case DSPROPERTY_EAXLISTENER_DECAYTIME:
2407 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2408 prim->eax_prop.flDecayTime, FLOAT);
2409 break;
2410 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
2411 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2412 prim->eax_prop.flDecayHFRatio, FLOAT);
2413 break;
2415 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
2416 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2417 prim->eax_prop.lReflections, LONG);
2418 break;
2419 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
2420 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2421 prim->eax_prop.flReflectionsDelay, FLOAT);
2422 break;
2424 case DSPROPERTY_EAXLISTENER_REVERB:
2425 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2426 prim->eax_prop.lReverb, LONG);
2427 break;
2428 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
2429 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2430 prim->eax_prop.flReverbDelay, FLOAT);
2431 break;
2433 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2434 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2435 prim->eax_prop.dwEnvironment, DWORD);
2436 break;
2438 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2439 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2440 prim->eax_prop.flEnvironmentSize, FLOAT);
2441 break;
2442 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2443 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2444 prim->eax_prop.flEnvironmentDiffusion, FLOAT);
2445 break;
2447 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2448 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2449 prim->eax_prop.flAirAbsorptionHF, FLOAT);
2450 break;
2452 case DSPROPERTY_EAXLISTENER_FLAGS:
2453 GET_PROP(&hr, pcbReturned, pPropData, cbPropData,
2454 prim->eax_prop.dwFlags, DWORD);
2455 break;
2457 default:
2458 hr = E_PROP_ID_UNSUPPORTED;
2459 FIXME("Unhandled propid: 0x%08lx\n", dwPropID);
2460 break;
2463 LeaveCriticalSection(This->crst);
2465 else
2466 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2467 #undef GET_PROP
2469 return hr;
2472 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2473 REFGUID guidPropSet, ULONG dwPropID,
2474 LPVOID pInstanceData, ULONG cbInstanceData,
2475 LPVOID pPropData, ULONG cbPropData)
2477 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2478 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2480 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2481 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2483 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2485 FIXME("Unhandled propset: DSPROPSETID_EAX20_BufferProperties\n");
2487 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2489 DS8Primary *prim = This->primary;
2490 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
2491 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
2493 EnterCriticalSection(prim->crst);
2494 setALContext(prim->ctx);
2496 hr = DSERR_INVALIDPARAM;
2497 if(prim->effect == 0)
2498 hr = E_PROP_ID_UNSUPPORTED;
2499 else switch(propid)
2501 case DSPROPERTY_EAXLISTENER_NONE: /* not setting any property, just applying */
2502 hr = DS_OK;
2503 break;
2505 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2506 do_allparams:
2507 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
2509 union {
2510 const void *v;
2511 const EAXLISTENERPROPERTIES *props;
2512 } data = { pPropData };
2514 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
2515 prim->eax_prop = *data.props;
2516 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DENSITY,
2517 clampF(powf(data.props->flEnvironmentSize, 3.0f) / 16.0f,
2518 0.0f, 1.0f)
2520 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
2521 data.props->flEnvironmentDiffusion);
2523 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2524 mB_to_gain(data.props->lRoom));
2525 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2526 mB_to_gain(data.props->lRoomHF));
2528 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2529 data.props->flRoomRolloffFactor);
2531 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_TIME,
2532 data.props->flDecayTime);
2533 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
2534 data.props->flDecayHFRatio);
2536 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
2537 mB_to_gain(data.props->lReflections));
2538 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
2539 data.props->flReflectionsDelay);
2541 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
2542 mB_to_gain(data.props->lReverb));
2543 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
2544 data.props->flReverbDelay);
2546 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2547 mBF_to_gain(data.props->flAirAbsorptionHF));
2549 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2550 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2551 AL_TRUE : AL_FALSE);
2553 checkALError();
2555 prim->dirty.bit.effect = 1;
2556 hr = DS_OK;
2558 break;
2560 case DSPROPERTY_EAXLISTENER_ROOM:
2561 if(cbPropData >= sizeof(LONG))
2563 union {
2564 const void *v;
2565 const LONG *l;
2566 } data = { pPropData };
2568 prim->eax_prop.lRoom = *data.l;
2569 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2570 mB_to_gain(prim->eax_prop.lRoom));
2571 checkALError();
2573 prim->dirty.bit.effect = 1;
2574 hr = DS_OK;
2576 break;
2577 case DSPROPERTY_EAXLISTENER_ROOMHF:
2578 if(cbPropData >= sizeof(LONG))
2580 union {
2581 const void *v;
2582 const LONG *l;
2583 } data = { pPropData };
2585 prim->eax_prop.lRoomHF = *data.l;
2586 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2587 mB_to_gain(prim->eax_prop.lRoomHF));
2588 checkALError();
2590 prim->dirty.bit.effect = 1;
2591 hr = DS_OK;
2593 break;
2595 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2596 if(cbPropData >= sizeof(FLOAT))
2598 union {
2599 const void *v;
2600 const FLOAT *fl;
2601 } data = { pPropData };
2603 prim->eax_prop.flRoomRolloffFactor = *data.fl;
2604 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2605 prim->eax_prop.flRoomRolloffFactor);
2606 checkALError();
2608 prim->dirty.bit.effect = 1;
2609 hr = DS_OK;
2611 break;
2613 case DSPROPERTY_EAXLISTENER_DECAYTIME:
2614 if(cbPropData >= sizeof(FLOAT))
2616 union {
2617 const void *v;
2618 const FLOAT *fl;
2619 } data = { pPropData };
2621 prim->eax_prop.flDecayTime = *data.fl;
2622 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_TIME,
2623 prim->eax_prop.flDecayTime);
2624 checkALError();
2626 prim->dirty.bit.effect = 1;
2627 hr = DS_OK;
2629 break;
2630 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO:
2631 if(cbPropData >= sizeof(FLOAT))
2633 union {
2634 const void *v;
2635 const FLOAT *fl;
2636 } data = { pPropData };
2638 prim->eax_prop.flDecayHFRatio = *data.fl;
2639 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
2640 prim->eax_prop.flDecayHFRatio);
2641 checkALError();
2643 prim->dirty.bit.effect = 1;
2644 hr = DS_OK;
2646 break;
2648 case DSPROPERTY_EAXLISTENER_REFLECTIONS:
2649 if(cbPropData >= sizeof(LONG))
2651 union {
2652 const void *v;
2653 const LONG *l;
2654 } data = { pPropData };
2656 prim->eax_prop.lReflections = *data.l;
2657 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
2658 mB_to_gain(prim->eax_prop.lReflections));
2659 checkALError();
2661 prim->dirty.bit.effect = 1;
2662 hr = DS_OK;
2664 break;
2665 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY:
2666 if(cbPropData >= sizeof(FLOAT))
2668 union {
2669 const void *v;
2670 const FLOAT *fl;
2671 } data = { pPropData };
2673 prim->eax_prop.flReflectionsDelay = *data.fl;
2674 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
2675 prim->eax_prop.flReflectionsDelay);
2676 checkALError();
2678 prim->dirty.bit.effect = 1;
2679 hr = DS_OK;
2681 break;
2683 case DSPROPERTY_EAXLISTENER_REVERB:
2684 if(cbPropData >= sizeof(LONG))
2686 union {
2687 const void *v;
2688 const LONG *l;
2689 } data = { pPropData };
2691 prim->eax_prop.lReverb = *data.l;
2692 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
2693 mB_to_gain(prim->eax_prop.lReverb));
2694 checkALError();
2696 prim->dirty.bit.effect = 1;
2697 hr = DS_OK;
2699 break;
2700 case DSPROPERTY_EAXLISTENER_REVERBDELAY:
2701 if(cbPropData >= sizeof(FLOAT))
2703 union {
2704 const void *v;
2705 const FLOAT *fl;
2706 } data = { pPropData };
2708 prim->eax_prop.flReverbDelay = *data.fl;
2709 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
2710 prim->eax_prop.flReverbDelay);
2711 checkALError();
2713 prim->dirty.bit.effect = 1;
2714 hr = DS_OK;
2716 break;
2718 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2719 if(cbPropData >= sizeof(DWORD))
2721 union {
2722 const void *v;
2723 const DWORD *dw;
2724 } data = { pPropData };
2726 if(*data.dw <= EAX_MAX_ENVIRONMENT)
2728 /* Get the environment index's default and pass it down to
2729 * ALLPARAMETERS */
2730 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2731 pPropData = (void*)&EnvironmentDefaults[*data.dw];
2732 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
2733 goto do_allparams;
2736 break;
2738 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2739 if(cbPropData >= sizeof(FLOAT))
2741 union {
2742 const void *v;
2743 const FLOAT *fl;
2744 } data = { pPropData };
2746 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2748 float scale = (*data.fl)/prim->eax_prop.flEnvironmentSize;
2750 prim->eax_prop.flEnvironmentSize = *data.fl;
2752 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2754 prim->eax_prop.flDecayTime *= scale;
2755 prim->eax_prop.flDecayTime = clampF(prim->eax_prop.flDecayTime, 0.1f, 20.0f);
2757 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2759 prim->eax_prop.lReflections -= gain_to_mB(scale);
2760 prim->eax_prop.lReflections = clampI(prim->eax_prop.lReflections, -10000, 1000);
2762 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2764 prim->eax_prop.flReflectionsDelay *= scale;
2765 prim->eax_prop.flReflectionsDelay = clampF(prim->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2767 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2769 prim->eax_prop.lReverb -= gain_to_mB(scale);
2770 prim->eax_prop.lReverb = clampI(prim->eax_prop.lReverb, -10000, 2000);
2772 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2774 prim->eax_prop.flReverbDelay *= scale;
2775 prim->eax_prop.flReverbDelay = clampF(prim->eax_prop.flReverbDelay, 0.0f, 0.1f);
2778 /* Pass the updated environment properties down to ALLPARAMETERS */
2779 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2780 pPropData = (void*)&prim->eax_prop;
2781 cbPropData = sizeof(prim->eax_prop);
2782 goto do_allparams;
2785 break;
2786 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2787 if(cbPropData >= sizeof(FLOAT))
2789 union {
2790 const void *v;
2791 const FLOAT *fl;
2792 } data = { pPropData };
2794 prim->eax_prop.flEnvironmentDiffusion = *data.fl;
2795 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
2796 prim->eax_prop.flEnvironmentDiffusion);
2797 checkALError();
2799 prim->dirty.bit.effect = 1;
2800 hr = DS_OK;
2802 break;
2804 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2805 if(cbPropData >= sizeof(FLOAT))
2807 union {
2808 const void *v;
2809 const FLOAT *fl;
2810 } data = { pPropData };
2812 prim->eax_prop.flAirAbsorptionHF = *data.fl;
2813 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2814 mBF_to_gain(prim->eax_prop.flAirAbsorptionHF));
2815 checkALError();
2817 prim->dirty.bit.effect = 1;
2818 hr = DS_OK;
2820 break;
2822 case DSPROPERTY_EAXLISTENER_FLAGS:
2823 if(cbPropData >= sizeof(DWORD))
2825 union {
2826 const void *v;
2827 const DWORD *dw;
2828 } data = { pPropData };
2830 prim->eax_prop.dwFlags = *data.dw;
2831 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2832 (prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2833 AL_TRUE : AL_FALSE);
2834 checkALError();
2836 prim->dirty.bit.effect = 1;
2837 hr = DS_OK;
2839 break;
2841 default:
2842 hr = E_PROP_ID_UNSUPPORTED;
2843 FIXME("Unhandled propid: 0x%08lx\n", propid);
2844 break;
2847 if(hr == DS_OK && immediate)
2848 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2850 popALContext();
2851 LeaveCriticalSection(prim->crst);
2853 else
2854 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2856 return hr;
2859 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2860 REFGUID guidPropSet, ULONG dwPropID,
2861 ULONG *pTypeSupport)
2863 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2864 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2866 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2868 if(!pTypeSupport)
2869 return E_POINTER;
2870 *pTypeSupport = 0;
2872 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2874 FIXME("Unhandled propset: DSPROPSETID_EAX20_BufferProperties\n");
2876 else if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2878 DS8Primary *prim = This->primary;
2880 EnterCriticalSection(This->crst);
2882 if(prim->effect == 0)
2883 hr = E_PROP_ID_UNSUPPORTED;
2884 else if(dwPropID == DSPROPERTY_EAXLISTENER_NONE)
2886 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
2887 hr = DS_OK;
2889 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2890 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2891 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2892 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2893 dwPropID == DSPROPERTY_EAXLISTENER_DECAYTIME ||
2894 dwPropID == DSPROPERTY_EAXLISTENER_DECAYHFRATIO ||
2895 dwPropID == DSPROPERTY_EAXLISTENER_REFLECTIONS ||
2896 dwPropID == DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY ||
2897 dwPropID == DSPROPERTY_EAXLISTENER_REVERB ||
2898 dwPropID == DSPROPERTY_EAXLISTENER_REVERBDELAY ||
2899 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2900 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2901 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2902 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2903 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2905 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2906 hr = DS_OK;
2908 else
2909 FIXME("Unhandled propid: 0x%08lx\n", dwPropID);
2911 LeaveCriticalSection(This->crst);
2913 else
2914 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2916 return hr;
2919 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2921 DS8BufferProp_QueryInterface,
2922 DS8BufferProp_AddRef,
2923 DS8BufferProp_Release,
2924 DS8BufferProp_Get,
2925 DS8BufferProp_Set,
2926 DS8BufferProp_QuerySupport