Improve returned error values
[dsound-openal.git] / buffer.c
blob4cad80ed245582dc6ac3e07f7ca92ace436a843c
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"
33 #include "dsound_private.h"
35 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
37 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
39 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
40 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
42 #ifndef E_PROP_ID_UNSUPPORTED
43 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
44 #endif
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
54 /* TODO: when bufferlost is set, return from all calls except initialize with
55 * DSERR_BUFFERLOST
57 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
58 static const IDirectSoundBufferVtbl DSBuffer_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, IDirectSoundBuffer_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 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
208 return NULL;
211 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
212 !prim->SupportedExt[EXT_MCFORMATS])
214 WARN("Multi-channel not available\n");
215 return NULL;
218 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
220 if(out->Samples.wValidBitsPerSample == 8)
222 switch(out->dwChannelMask)
224 case MONO: return "AL_FORMAT_MONO8";
225 case STEREO: return "AL_FORMAT_STEREO8";
226 case REAR: return "AL_FORMAT_REAR8";
227 case QUAD: return "AL_FORMAT_QUAD8";
228 case X5DOT1: return "AL_FORMAT_51CHN8";
229 case X6DOT1: return "AL_FORMAT_61CHN8";
230 case X7DOT1: return "AL_FORMAT_71CHN8";
233 else if(out->Samples.wValidBitsPerSample == 16)
235 switch(out->dwChannelMask)
237 case MONO: return "AL_FORMAT_MONO16";
238 case STEREO: return "AL_FORMAT_STEREO16";
239 case REAR: return "AL_FORMAT_REAR16";
240 case QUAD: return "AL_FORMAT_QUAD16";
241 case X5DOT1: return "AL_FORMAT_51CHN16";
242 case X6DOT1: return "AL_FORMAT_61CHN16";
243 case X7DOT1: return "AL_FORMAT_71CHN16";
247 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#lx)\n",
248 out->Samples.wValidBitsPerSample, out->dwChannelMask);
249 return NULL;
251 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
252 prim->SupportedExt[EXT_FLOAT32])
254 if(out->Samples.wValidBitsPerSample == 32)
256 switch(out->dwChannelMask)
258 case MONO: return "AL_FORMAT_MONO_FLOAT32";
259 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
260 case REAR: return "AL_FORMAT_REAR32";
261 case QUAD: return "AL_FORMAT_QUAD32";
262 case X5DOT1: return "AL_FORMAT_51CHN32";
263 case X6DOT1: return "AL_FORMAT_61CHN32";
264 case X7DOT1: return "AL_FORMAT_71CHN32";
267 else
269 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
270 return NULL;
273 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
274 out->Samples.wValidBitsPerSample, out->dwChannelMask);
275 return NULL;
277 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
278 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
279 return NULL;
282 static void DS8Data_Release(DS8Data *This);
283 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
285 HRESULT hr = DSERR_INVALIDPARAM;
286 const WAVEFORMATEX *format;
287 const char *fmt_str = NULL;
288 DS8Data *pBuffer;
290 format = desc->lpwfxFormat;
291 TRACE("Requested buffer format:\n"
292 " FormatTag = 0x%04x\n"
293 " Channels = %d\n"
294 " SamplesPerSec = %lu\n"
295 " AvgBytesPerSec = %lu\n"
296 " BlockAlign = %d\n"
297 " BitsPerSample = %d\n",
298 format->wFormatTag, format->nChannels,
299 format->nSamplesPerSec, format->nAvgBytesPerSec,
300 format->nBlockAlign, format->wBitsPerSample);
302 if(format->nSamplesPerSec <= 0)
304 WARN("Invalid SamplesPerSec specified\n");
305 return DSERR_INVALIDPARAM;
307 if(format->nBlockAlign <= 0)
309 WARN("Invalid BlockAlign specified\n");
310 return DSERR_INVALIDPARAM;
313 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
314 * will need the EAX-RAM extension. Currently, we just tell the app it
315 * gets what it wanted. */
316 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
317 if(!pBuffer) return E_OUTOFMEMORY;
318 pBuffer->ref = 1;
319 pBuffer->primary = prim;
321 pBuffer->dsbflags = desc->dwFlags;
322 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
324 WARN("Hardware and software location requested\n");
325 goto fail;
327 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
328 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
330 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
331 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
333 hr = DSERR_BUFFERTOOSMALL;
334 if(pBuffer->buf_size < DSBSIZE_MIN)
335 goto fail;
337 hr = DSERR_INVALIDPARAM;
338 if(pBuffer->buf_size > DSBSIZE_MAX)
339 goto fail;
341 if(format->wFormatTag == WAVE_FORMAT_PCM)
342 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
343 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
344 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
345 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
347 const WAVEFORMATEXTENSIBLE *wfe;
349 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
350 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
351 goto fail;
353 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
354 TRACE("Extensible values:\n"
355 " Samples = %d\n"
356 " ChannelMask = 0x%lx\n"
357 " SubFormat = %s\n",
358 wfe->Samples.wReserved, wfe->dwChannelMask,
359 debugstr_guid(&wfe->SubFormat));
361 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
363 else
364 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
365 if(!fmt_str) goto fail;
367 pBuffer->buf_format = alGetEnumValue(fmt_str);
368 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
369 pBuffer->buf_format == -1)
371 WARN("Could not get OpenAL format from %s\n", fmt_str);
372 goto fail;
375 hr = DSERR_INVALIDPARAM;
376 if(format->nBlockAlign != format->nChannels*format->wBitsPerSample/8)
378 WARN("Incorrect BlockAlign specified\n");
379 goto fail;
381 if(format->nAvgBytesPerSec != format->nBlockAlign*format->nSamplesPerSec)
383 WARN("Incorrect AvgBytesPerSec specified\n");
384 goto fail;
387 hr = E_OUTOFMEMORY;
388 if(!prim->SupportedExt[SOFTX_MAP_BUFFER])
390 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
391 if(!pBuffer->data) goto fail;
393 alGenBuffers(1, &pBuffer->bid);
394 checkALError();
396 else
398 const ALbitfieldSOFT map_bits = AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT |
399 AL_MAP_PERSISTENT_BIT_SOFT;
400 alGenBuffers(1, &pBuffer->bid);
401 prim->ExtAL->BufferStorageSOFT(pBuffer->bid, pBuffer->buf_format, NULL, pBuffer->buf_size,
402 pBuffer->format.Format.nSamplesPerSec, map_bits);
403 pBuffer->data = prim->ExtAL->MapBufferSOFT(pBuffer->bid, 0, pBuffer->buf_size, map_bits);
404 checkALError();
406 if(!pBuffer->data) goto fail;
409 *ppv = pBuffer;
410 return S_OK;
412 fail:
413 DS8Data_Release(pBuffer);
414 return hr;
417 static void DS8Data_AddRef(DS8Data *data)
419 InterlockedIncrement(&data->ref);
422 /* This function is always called with the device lock held */
423 static void DS8Data_Release(DS8Data *This)
425 if(InterlockedDecrement(&This->ref)) return;
427 TRACE("Deleting %p\n", This);
428 if(This->bid)
430 DS8Primary *prim = This->primary;
431 if(prim->SupportedExt[SOFTX_MAP_BUFFER])
433 prim->ExtAL->UnmapBufferSOFT(This->bid);
434 This->data = NULL;
436 alDeleteBuffers(1, &This->bid);
437 checkALError();
439 HeapFree(GetProcessHeap(), 0, This->data);
440 HeapFree(GetProcessHeap(), 0, This);
444 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
446 DS8Buffer *This = NULL;
447 HRESULT hr;
448 DWORD i;
450 *ppv = NULL;
451 EnterCriticalSection(prim->crst);
452 for(i = 0;i < prim->NumBufferGroups;++i)
454 if(prim->BufferGroups[i].FreeBuffers)
456 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
457 This = prim->BufferGroups[i].Buffers + idx;
458 memset(This, 0, sizeof(*This));
459 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
460 break;
463 LeaveCriticalSection(prim->crst);
464 if(!This)
466 WARN("Allocating extra DS8Buffer\n");
467 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
468 if(!This) return DSERR_OUTOFMEMORY;
471 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
472 This->IDirectSoundBuffer_iface.lpVtbl = &DSBuffer_Vtbl;
473 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
474 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
475 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
477 This->primary = prim;
478 This->ctx = prim->ctx;
479 This->ExtAL = prim->ExtAL;
480 This->crst = prim->crst;
481 This->ref = This->all_ref = 1;
483 if(orig)
485 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
486 hr = DSERR_BUFFERLOST;
487 if(org->bufferlost)
488 goto fail;
489 DS8Data_AddRef(org->buffer);
490 This->buffer = org->buffer;
493 /* Disable until initialized.. */
494 This->ds3dmode = DS3DMODE_DISABLE;
496 *ppv = This;
497 return DS_OK;
499 fail:
500 DS8Buffer_Destroy(This);
501 return hr;
504 void DS8Buffer_Destroy(DS8Buffer *This)
506 DS8Primary *prim = This->primary;
507 DWORD i;
509 TRACE("Destroying %p\n", This);
511 EnterCriticalSection(prim->crst);
512 /* Remove from list, if in list */
513 for(i = 0;i < prim->nnotifies;++i)
515 if(This == prim->notifies[i])
517 prim->notifies[i] = prim->notifies[--prim->nnotifies];
518 break;
522 setALContext(This->ctx);
523 if(This->source)
525 alSourceStop(This->source);
526 alSourcei(This->source, AL_BUFFER, 0);
527 checkALError();
529 prim->sources[prim->parent->share->nsources++] = This->source;
530 This->source = 0;
532 if(This->stream_bids[0])
533 alDeleteBuffers(QBUFFERS, This->stream_bids);
535 if(This->buffer)
536 DS8Data_Release(This->buffer);
538 popALContext();
540 HeapFree(GetProcessHeap(), 0, This->notify);
542 for(i = 0;i < prim->NumBufferGroups;++i)
544 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
545 if(idx < 64)
547 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
548 This = NULL;
549 break;
552 LeaveCriticalSection(prim->crst);
554 HeapFree(GetProcessHeap(), 0, This);
558 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
560 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
562 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
564 *ppv = NULL;
565 if(IsEqualIID(riid, &IID_IUnknown))
566 *ppv = &This->IDirectSoundBuffer8_iface;
567 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
568 *ppv = &This->IDirectSoundBuffer_iface;
569 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
571 if(This->primary->parent->is_8)
572 *ppv = &This->IDirectSoundBuffer8_iface;
574 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
576 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
577 *ppv = &This->IDirectSound3DBuffer_iface;
579 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
581 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
582 *ppv = &This->IDirectSoundNotify_iface;
584 else if(IsEqualIID(riid, &IID_IKsPropertySet))
585 *ppv = &This->IKsPropertySet_iface;
586 else
587 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
589 if(*ppv)
591 IUnknown_AddRef((IUnknown*)*ppv);
592 return S_OK;
595 return E_NOINTERFACE;
598 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
600 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
601 LONG ret;
603 InterlockedIncrement(&This->all_ref);
604 ret = InterlockedIncrement(&This->ref);
605 TRACE("new refcount %ld\n", ret);
607 return ret;
610 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
612 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
613 LONG ret;
615 ret = InterlockedDecrement(&This->ref);
616 TRACE("new refcount %ld\n", ret);
617 if(InterlockedDecrement(&This->all_ref) == 0)
618 DS8Buffer_Destroy(This);
620 return ret;
623 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
625 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
627 TRACE("(%p)->(%p)\n", iface, caps);
629 if(!caps || caps->dwSize < sizeof(*caps))
631 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
632 return DSERR_INVALIDPARAM;
635 caps->dwFlags = This->buffer->dsbflags;
636 caps->dwBufferBytes = This->buffer->buf_size;
637 caps->dwUnlockTransferRate = 4096;
638 caps->dwPlayCpuOverhead = 0;
639 return S_OK;
642 HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
644 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
645 ALsizei writecursor, pos;
646 DS8Data *data;
648 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
650 data = This->buffer;
651 if(This->segsize != 0)
653 ALint queued = QBUFFERS;
654 ALint status = 0;
655 ALint ofs = 0;
657 EnterCriticalSection(This->crst);
659 setALContext(This->ctx);
660 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
661 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
662 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
663 checkALError();
664 popALContext();
666 if(status == AL_STOPPED)
667 pos = This->segsize*queued + This->queue_base;
668 else
669 pos = ofs + This->queue_base;
670 if(pos >= data->buf_size)
672 if(This->islooping)
673 pos %= data->buf_size;
674 else if(This->isplaying)
676 pos = data->buf_size;
677 alSourceStop(This->source);
678 alSourcei(This->source, AL_BUFFER, 0);
679 This->curidx = 0;
680 This->isplaying = FALSE;
683 if(This->isplaying)
684 writecursor = (This->segsize*QBUFFERS + pos) % data->buf_size;
685 else
686 writecursor = pos % data->buf_size;
688 LeaveCriticalSection(This->crst);
690 else
692 const WAVEFORMATEX *format = &data->format.Format;
693 ALint status = 0;
694 ALint ofs = 0;
696 setALContext(This->ctx);
697 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
698 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
699 checkALError();
700 popALContext();
702 /* AL_STOPPED means the source naturally reached its end, where
703 * DirectSound's position should be at the end (OpenAL reports a 0
704 * position). The Stop method correlates to pausing, which would put
705 * the source into an AL_PAUSED state and hold its current position.
707 pos = (status == AL_STOPPED) ? data->buf_size : ofs;
708 if(status == AL_PLAYING)
710 writecursor = format->nSamplesPerSec / This->primary->refresh;
711 writecursor *= format->nBlockAlign;
713 else
714 writecursor = 0;
715 writecursor = (writecursor + pos) % data->buf_size;
717 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
719 if(pos > data->buf_size)
721 ERR("playpos > buf_size\n");
722 pos %= data->buf_size;
724 if(writecursor >= data->buf_size)
726 ERR("writepos >= buf_size\n");
727 writecursor %= data->buf_size;
730 if(playpos) *playpos = pos;
731 if(curpos) *curpos = writecursor;
733 return S_OK;
736 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
738 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
739 HRESULT hr = S_OK;
740 UINT size;
742 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
744 if(!wfx && !written)
746 WARN("Cannot report format or format size\n");
747 return DSERR_INVALIDPARAM;
750 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
751 if(wfx)
753 if(allocated < size)
754 hr = DSERR_INVALIDPARAM;
755 else
756 memcpy(wfx, &This->buffer->format.Format, size);
758 if(written)
759 *written = size;
761 return hr;
764 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
766 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
767 HRESULT hr;
769 TRACE("(%p)->(%p)\n", iface, vol);
771 if(!vol)
773 WARN("Invalid pointer\n");
774 return DSERR_INVALIDPARAM;
777 hr = DSERR_CONTROLUNAVAIL;
778 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
779 WARN("Volume control not set\n");
780 else
782 ALfloat gain = 1.0f;
784 setALContext(This->ctx);
785 alGetSourcef(This->source, AL_GAIN, &gain);
786 checkALError();
787 popALContext();
789 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
790 hr = DS_OK;
793 return hr;
796 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
798 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
799 HRESULT hr;
801 TRACE("(%p)->(%p)\n", iface, pan);
803 if(!pan)
805 WARN("Invalid pointer\n");
806 return DSERR_INVALIDPARAM;
809 hr = DSERR_CONTROLUNAVAIL;
810 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
811 WARN("Panning control not set\n");
812 else
814 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
815 *pan = 0;
816 else
818 ALfloat pos[3];
820 setALContext(This->ctx);
821 alGetSourcefv(This->source, AL_POSITION, pos);
822 checkALError();
823 popALContext();
825 *pan = clampI((LONG)((pos[0]+0.5f)*(DSBPAN_RIGHT-DSBPAN_LEFT) + 0.5f) + DSBPAN_LEFT,
826 DSBPAN_LEFT, DSBPAN_RIGHT);
828 hr = DS_OK;
831 return hr;
834 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
836 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
837 HRESULT hr;
839 TRACE("(%p)->(%p)\n", iface, freq);
841 if(!freq)
843 WARN("Invalid pointer\n");
844 return DSERR_INVALIDPARAM;
847 hr = DSERR_CONTROLUNAVAIL;
848 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
849 WARN("Frequency control not set\n");
850 else
852 ALfloat pitch = 1.0f;
854 setALContext(This->ctx);
855 alGetSourcefv(This->source, AL_PITCH, &pitch);
856 checkALError();
857 popALContext();
859 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
860 hr = DS_OK;
863 return hr;
866 HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
868 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
869 ALint state, looping;
871 TRACE("(%p)->(%p)\n", iface, status);
873 if(!status)
875 WARN("Invalid pointer\n");
876 return DSERR_INVALIDPARAM;
878 *status = 0;
880 if(This->segsize == 0)
882 setALContext(This->ctx);
883 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
884 alGetSourcei(This->source, AL_LOOPING, &looping);
885 checkALError();
886 popALContext();
888 else
890 EnterCriticalSection(This->crst);
892 setALContext(This->ctx);
893 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
894 checkALError();
895 popALContext();
897 if(state != AL_PLAYING)
898 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
899 looping = This->islooping;
901 LeaveCriticalSection(This->crst);
904 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
906 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
907 *status |= DSBSTATUS_LOCSOFTWARE;
908 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
909 *status |= DSBSTATUS_LOCHARDWARE;
911 if(state == AL_PLAYING)
912 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
914 TRACE("%p status = 0x%08lx\n", This, *status);
915 return S_OK;
918 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
920 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
921 DS3DBUFFER *ds3dbuffer;
922 DS8Primary *prim;
923 DS8Data *data;
924 HRESULT hr;
926 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
928 EnterCriticalSection(This->crst);
929 setALContext(This->ctx);
931 hr = DSERR_ALREADYINITIALIZED;
932 if(This->source) goto out;
934 if(!This->buffer)
936 hr = DSERR_INVALIDPARAM;
937 if(!desc)
939 WARN("Missing DSound buffer description\n");
940 goto out;
942 if(!desc->lpwfxFormat)
944 WARN("Missing buffer format (%p)\n", This);
945 goto out;
947 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
949 if(This->primary->parent->is_8)
951 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
952 * buffers */
953 WARN("Can't create multi-channel 3D buffers\n");
954 goto out;
956 ERR("Multi-channel 3D sounds are not spatialized\n");
959 hr = DS8Data_Create(&This->buffer, desc, This->primary);
960 if(FAILED(hr)) goto out;
962 data = This->buffer;
963 if(data->format.Format.wBitsPerSample == 8)
964 memset(data->data, 0x80, data->buf_size);
965 else
966 memset(data->data, 0x00, data->buf_size);
969 prim = This->primary;
970 data = This->buffer;
971 if(!(data->dsbflags&DSBCAPS_STATIC) && !prim->SupportedExt[SOFTX_MAP_BUFFER])
973 This->segsize = (data->format.Format.nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
974 This->segsize = clampI(This->segsize, data->format.Format.nBlockAlign, 2048);
975 This->segsize += data->format.Format.nBlockAlign - 1;
976 This->segsize -= This->segsize%data->format.Format.nBlockAlign;
978 alGenBuffers(QBUFFERS, This->stream_bids);
979 checkALError();
982 hr = DSERR_ALLOCATED;
983 if(!prim->parent->share->nsources)
984 goto out;
986 This->source = prim->sources[--(prim->parent->share->nsources)];
987 alSourceRewind(This->source);
988 alSourcef(This->source, AL_GAIN, 1.0f);
989 alSourcef(This->source, AL_PITCH, 1.0f);
990 checkALError();
992 ds3dbuffer = &This->params;
993 ds3dbuffer->dwSize = sizeof(This->params);
994 ds3dbuffer->vPosition.x = 0.0f;
995 ds3dbuffer->vPosition.y = 0.0f;
996 ds3dbuffer->vPosition.z = 0.0f;
997 ds3dbuffer->vVelocity.x = 0.0f;
998 ds3dbuffer->vVelocity.y = 0.0f;
999 ds3dbuffer->vVelocity.z = 0.0f;
1000 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1001 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1002 ds3dbuffer->vConeOrientation.x = 0.0f;
1003 ds3dbuffer->vConeOrientation.y = 0.0f;
1004 ds3dbuffer->vConeOrientation.z = 1.0f;
1005 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1006 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1007 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1008 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1010 if((data->dsbflags&DSBCAPS_CTRL3D))
1012 union BufferParamFlags dirty = { 0 };
1014 if(prim->auxslot != 0)
1015 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, AL_FILTER_NULL);
1017 dirty.bit.pos = 1;
1018 dirty.bit.vel = 1;
1019 dirty.bit.cone_angles = 1;
1020 dirty.bit.cone_orient = 1;
1021 dirty.bit.cone_outsidevolume = 1;
1022 dirty.bit.min_distance = 1;
1023 dirty.bit.max_distance = 1;
1024 dirty.bit.mode = 1;
1025 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
1026 checkALError();
1028 else
1030 ALuint source = This->source;
1032 if(prim->auxslot != 0)
1034 /* Simple hack to make reverb affect non-3D sounds too */
1035 alSource3i(source, AL_AUXILIARY_SEND_FILTER, prim->auxslot, 0, AL_FILTER_NULL);
1036 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1039 /* Non-3D sources aren't distance attenuated */
1040 This->ds3dmode = DS3DMODE_DISABLE;
1041 alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
1042 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1043 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1044 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1045 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1046 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1047 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1048 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1049 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1050 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1051 checkALError();
1053 hr = S_OK;
1055 out:
1056 popALContext();
1057 LeaveCriticalSection(This->crst);
1059 return hr;
1062 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1064 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1065 DWORD remain;
1067 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1069 if(!ptr1 || !len1)
1071 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1072 return DSERR_INVALIDPARAM;
1075 *ptr1 = NULL;
1076 *len1 = 0;
1077 if(ptr2) *ptr2 = NULL;
1078 if(len2) *len2 = 0;
1080 if((flags&DSBLOCK_FROMWRITECURSOR))
1081 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1082 else if(ofs >= (DWORD)This->buffer->buf_size)
1084 WARN("Invalid ofs %lu\n", ofs);
1085 return DSERR_INVALIDPARAM;
1087 if((flags&DSBLOCK_ENTIREBUFFER))
1088 bytes = This->buffer->buf_size;
1089 else if(bytes > (DWORD)This->buffer->buf_size)
1091 WARN("Invalid size %lu\n", bytes);
1092 return DSERR_INVALIDPARAM;
1095 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1097 WARN("Already locked\n");
1098 return DSERR_INVALIDPARAM;
1101 *ptr1 = This->buffer->data + ofs;
1102 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1104 *len1 = This->buffer->buf_size - ofs;
1105 remain = bytes - *len1;
1107 else
1109 *len1 = bytes;
1110 remain = 0;
1113 if(ptr2 && len2 && remain)
1115 *ptr2 = This->buffer->data;
1116 *len2 = remain;
1119 return DS_OK;
1122 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1124 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1125 ALint state = AL_STOPPED;
1126 DS8Data *data;
1127 HRESULT hr;
1129 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1131 EnterCriticalSection(This->crst);
1132 setALContext(This->ctx);
1134 hr = DSERR_BUFFERLOST;
1135 if(This->bufferlost)
1137 WARN("Buffer %p lost\n", This);
1138 goto out;
1141 data = This->buffer;
1142 if((data->dsbflags&DSBCAPS_LOCDEFER))
1144 if(!(data->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1146 if(flags & DSBPLAY_LOCSOFTWARE)
1147 data->dsbflags |= DSBCAPS_LOCSOFTWARE;
1148 else
1149 data->dsbflags |= DSBCAPS_LOCHARDWARE;
1152 else if(prio)
1154 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1155 hr = DSERR_INVALIDPARAM;
1156 goto out;
1159 if(This->segsize != 0)
1161 This->islooping = !!(flags&DSBPLAY_LOOPING);
1162 if(This->isplaying) state = AL_PLAYING;
1164 else
1166 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1167 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1169 checkALError();
1171 hr = S_OK;
1172 if(state == AL_PLAYING)
1173 goto out;
1175 if(This->segsize == 0)
1177 if(state != AL_PAUSED)
1178 alSourcei(This->source, AL_BUFFER, data->bid);
1179 alSourcePlay(This->source);
1181 else
1183 alSourceRewind(This->source);
1184 alSourcei(This->source, AL_BUFFER, 0);
1185 This->queue_base = This->data_offset % data->buf_size;
1186 This->curidx = 0;
1188 if(alGetError() != AL_NO_ERROR)
1190 ERR("Couldn't start source\n");
1191 alSourcei(This->source, AL_BUFFER, 0);
1192 checkALError();
1193 hr = DSERR_GENERIC;
1194 goto out;
1196 This->isplaying = TRUE;
1197 This->playflags = flags;
1199 if(This->nnotify)
1200 DS8Buffer_addnotify(This);
1202 out:
1203 popALContext();
1204 LeaveCriticalSection(This->crst);
1205 return hr;
1208 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1210 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1211 DS8Data *data;
1213 TRACE("(%p)->(%lu)\n", iface, pos);
1215 data = This->buffer;
1216 if(pos >= (DWORD)data->buf_size)
1217 return DSERR_INVALIDPARAM;
1218 pos -= pos%data->format.Format.nBlockAlign;
1220 EnterCriticalSection(This->crst);
1222 if(This->segsize != 0)
1224 if(This->isplaying)
1226 setALContext(This->ctx);
1227 /* Perform a flush, so the next timer update will restart at the
1228 * proper position */
1229 alSourceRewind(This->source);
1230 alSourcei(This->source, AL_BUFFER, 0);
1231 checkALError();
1232 popALContext();
1234 This->queue_base = This->data_offset = pos;
1235 This->curidx = 0;
1237 else
1239 setALContext(This->ctx);
1240 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1241 popALContext();
1243 This->lastpos = pos;
1245 LeaveCriticalSection(This->crst);
1246 return DS_OK;
1249 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1251 /* This call only works on primary buffers */
1252 WARN("(%p)->(%p)\n", iface, wfx);
1253 return DSERR_INVALIDCALL;
1256 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1258 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1259 HRESULT hr = S_OK;
1261 TRACE("(%p)->(%ld)\n", iface, vol);
1263 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1265 WARN("Invalid volume (%ld)\n", vol);
1266 return DSERR_INVALIDPARAM;
1269 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1270 hr = DSERR_CONTROLUNAVAIL;
1271 if(SUCCEEDED(hr))
1273 ALfloat fvol = mB_to_gain(vol);
1274 setALContext(This->ctx);
1275 alSourcef(This->source, AL_GAIN, fvol);
1276 popALContext();
1279 return hr;
1282 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1284 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1285 HRESULT hr = S_OK;
1287 TRACE("(%p)->(%ld)\n", iface, pan);
1289 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1291 WARN("invalid parameter: pan = %ld\n", pan);
1292 return DSERR_INVALIDPARAM;
1295 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1296 hr = DSERR_CONTROLUNAVAIL;
1297 else
1299 if(!(This->buffer->dsbflags&DSBCAPS_CTRL3D))
1301 ALfloat pos[3];
1302 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1303 pos[1] = 0.0f;
1304 /* NOTE: Strict movement along the X plane can cause the sound to
1305 * jump between left and right sharply. Using a curved path helps
1306 * smooth it out.
1308 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1310 setALContext(This->ctx);
1311 alSourcefv(This->source, AL_POSITION, pos);
1312 checkALError();
1313 popALContext();
1315 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1316 FIXME("Panning for multi-channel buffers is not supported\n");
1320 return hr;
1323 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1325 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1326 HRESULT hr = S_OK;
1328 TRACE("(%p)->(%lu)\n", iface, freq);
1330 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1332 WARN("invalid parameter: freq = %lu\n", freq);
1333 return DSERR_INVALIDPARAM;
1336 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1337 hr = DSERR_CONTROLUNAVAIL;
1338 else
1340 ALfloat pitch = 1.0f;
1341 if(freq != DSBFREQUENCY_ORIGINAL)
1342 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1344 setALContext(This->ctx);
1345 alSourcef(This->source, AL_PITCH, pitch);
1346 checkALError();
1347 popALContext();
1350 return hr;
1353 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1355 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1357 TRACE("(%p)->()\n", iface);
1359 EnterCriticalSection(This->crst);
1360 setALContext(This->ctx);
1362 alSourcePause(This->source);
1363 checkALError();
1365 This->isplaying = FALSE;
1367 popALContext();
1368 LeaveCriticalSection(This->crst);
1370 return S_OK;
1373 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1375 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1376 DS8Data *buf = This->buffer;
1377 DWORD bufsize = buf->buf_size;
1378 DWORD_PTR ofs1, ofs2;
1379 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1380 HRESULT hr;
1382 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1384 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1386 WARN("Not locked\n");
1387 return DSERR_INVALIDPARAM;
1390 hr = DSERR_INVALIDPARAM;
1391 /* Make sure offset is between boundary and boundary + bufsize */
1392 ofs1 = (DWORD_PTR)ptr1;
1393 ofs2 = (DWORD_PTR)ptr2;
1394 if(ofs1 < boundary || (ofs2 && ofs2 != boundary))
1395 goto out;
1396 ofs1 -= boundary;
1397 ofs2 = 0;
1398 if(bufsize-ofs1 < len1 || len2 > ofs1)
1399 goto out;
1400 if(!ptr2)
1401 len2 = 0;
1403 hr = DS_OK;
1404 if(!len1 && !len2)
1405 goto out;
1407 if(This->primary->SupportedExt[SOFTX_MAP_BUFFER])
1409 setALContext(This->ctx);
1410 This->ExtAL->FlushMappedBufferSOFT(buf->bid, 0, buf->buf_size);
1411 checkALError();
1412 popALContext();
1414 else if(This->segsize == 0)
1416 setALContext(This->ctx);
1417 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1418 buf->format.Format.nSamplesPerSec);
1419 checkALError();
1420 popALContext();
1423 out:
1424 if(hr != S_OK)
1425 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1426 return hr;
1429 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1431 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1432 HRESULT hr;
1434 TRACE("(%p)->()\n", iface);
1436 EnterCriticalSection(This->crst);
1437 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1438 iface == This->primary->write_emu)
1440 This->bufferlost = 0;
1441 hr = S_OK;
1443 else
1444 hr = DSERR_BUFFERLOST;
1445 LeaveCriticalSection(This->crst);
1447 return hr;
1450 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1452 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1453 ALenum state = AL_INITIAL;
1454 DS8Data *data;
1455 HRESULT hr;
1456 DWORD i;
1458 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1460 data = This->buffer;
1461 if(!(data->dsbflags&DSBCAPS_CTRLFX))
1463 WARN("FX control not set\n");
1464 return DSERR_CONTROLUNAVAIL;
1467 if(data->locked)
1469 WARN("Buffer is locked\n");
1470 return DSERR_INVALIDCALL;
1473 EnterCriticalSection(This->crst);
1474 setALContext(This->ctx);
1476 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1477 checkALError();
1478 if(This->segsize != 0 && state != AL_PLAYING)
1479 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1480 if(state == AL_PLAYING)
1482 WARN("Buffer is playing\n");
1483 hr = DSERR_INVALIDCALL;
1484 goto done;
1487 hr = DSERR_INVALIDPARAM;
1488 if(fxcount == 0)
1490 if(desc || rescodes)
1492 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1493 goto done;
1496 /* No effects; we can handle that */
1497 hr = DS_OK;
1498 goto done;
1501 if(!desc || !rescodes)
1503 WARN("NULL desc and/or result pointer specified.\n");
1504 goto done;
1507 /* We don't (currently) handle DSound effects */
1508 for(i = 0;i < fxcount;++i)
1510 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1511 rescodes[i] = DSFXR_FAILED;
1513 hr = DS_INCOMPLETE;
1515 done:
1516 popALContext();
1517 LeaveCriticalSection(This->crst);
1519 return hr;
1522 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1524 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1526 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1528 /* effects aren't supported at the moment.. */
1529 if(fxcount != 0 || rescodes)
1531 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1532 return DSERR_INVALIDPARAM;
1535 EnterCriticalSection(This->crst);
1536 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1538 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1539 if((flags&DSBPLAY_LOCSOFTWARE))
1540 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1541 else
1542 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1544 LeaveCriticalSection(This->crst);
1546 return S_OK;
1549 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1551 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1552 return E_NOTIMPL;
1555 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1556 DS8Buffer_QueryInterface,
1557 DS8Buffer_AddRef,
1558 DS8Buffer_Release,
1559 DS8Buffer_GetCaps,
1560 DS8Buffer_GetCurrentPosition,
1561 DS8Buffer_GetFormat,
1562 DS8Buffer_GetVolume,
1563 DS8Buffer_GetPan,
1564 DS8Buffer_GetFrequency,
1565 DS8Buffer_GetStatus,
1566 DS8Buffer_Initialize,
1567 DS8Buffer_Lock,
1568 DS8Buffer_Play,
1569 DS8Buffer_SetCurrentPosition,
1570 DS8Buffer_SetFormat,
1571 DS8Buffer_SetVolume,
1572 DS8Buffer_SetPan,
1573 DS8Buffer_SetFrequency,
1574 DS8Buffer_Stop,
1575 DS8Buffer_Unlock,
1576 DS8Buffer_Restore,
1577 DS8Buffer_SetFX,
1578 DS8Buffer_AcquireResources,
1579 DS8Buffer_GetObjectInPath
1583 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, void **ppv)
1585 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1586 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1589 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer *iface)
1591 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1592 return DS8Buffer_AddRef(&This->IDirectSoundBuffer8_iface);
1595 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer *iface)
1597 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1598 return DS8Buffer_Release(&This->IDirectSoundBuffer8_iface);
1601 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1603 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1604 return DS8Buffer_GetCaps(&This->IDirectSoundBuffer8_iface, caps);
1607 static HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
1609 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1610 return DS8Buffer_GetCurrentPosition(&This->IDirectSoundBuffer8_iface, playpos, curpos);
1613 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1615 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1616 return DS8Buffer_GetFormat(&This->IDirectSoundBuffer8_iface, wfx, allocated, written);
1619 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
1621 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1622 return DS8Buffer_GetVolume(&This->IDirectSoundBuffer8_iface, vol);
1625 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer *iface, LONG *pan)
1627 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1628 return DS8Buffer_GetPan(&This->IDirectSoundBuffer8_iface, pan);
1631 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
1633 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1634 return DS8Buffer_GetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1637 static HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
1639 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1640 return DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, status);
1643 static HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1645 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1646 return DS8Buffer_Initialize(&This->IDirectSoundBuffer8_iface, ds, desc);
1649 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1651 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1652 return DS8Buffer_Lock(&This->IDirectSoundBuffer8_iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1655 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD prio, DWORD flags)
1657 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1658 return DS8Buffer_Play(&This->IDirectSoundBuffer8_iface, res1, prio, flags);
1661 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
1663 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1664 return DS8Buffer_SetCurrentPosition(&This->IDirectSoundBuffer8_iface, pos);
1667 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
1669 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1670 return DS8Buffer_SetFormat(&This->IDirectSoundBuffer8_iface, wfx);
1673 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer *iface, LONG vol)
1675 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1676 return DS8Buffer_SetVolume(&This->IDirectSoundBuffer8_iface, vol);
1679 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer *iface, LONG pan)
1681 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1682 return DS8Buffer_SetPan(&This->IDirectSoundBuffer8_iface, pan);
1685 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
1687 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1688 return DS8Buffer_SetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1691 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer *iface)
1693 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1694 return DS8Buffer_Stop(&This->IDirectSoundBuffer8_iface);
1697 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1699 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1700 return DS8Buffer_Unlock(&This->IDirectSoundBuffer8_iface, ptr1, len1, ptr2, len2);
1703 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer *iface)
1705 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1706 return DS8Buffer_Restore(&This->IDirectSoundBuffer8_iface);
1709 static const IDirectSoundBufferVtbl DSBuffer_Vtbl = {
1710 DSBuffer_QueryInterface,
1711 DSBuffer_AddRef,
1712 DSBuffer_Release,
1713 DSBuffer_GetCaps,
1714 DSBuffer_GetCurrentPosition,
1715 DSBuffer_GetFormat,
1716 DSBuffer_GetVolume,
1717 DSBuffer_GetPan,
1718 DSBuffer_GetFrequency,
1719 DSBuffer_GetStatus,
1720 DSBuffer_Initialize,
1721 DSBuffer_Lock,
1722 DSBuffer_Play,
1723 DSBuffer_SetCurrentPosition,
1724 DSBuffer_SetFormat,
1725 DSBuffer_SetVolume,
1726 DSBuffer_SetPan,
1727 DSBuffer_SetFrequency,
1728 DSBuffer_Stop,
1729 DSBuffer_Unlock,
1730 DSBuffer_Restore
1734 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, LONG flags)
1736 const ALuint source = This->source;
1737 union BufferParamFlags dirty = { flags };
1739 if(dirty.bit.pos)
1740 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1741 -params->vPosition.z);
1742 if(dirty.bit.vel)
1743 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1744 -params->vVelocity.z);
1745 if(dirty.bit.cone_angles)
1747 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1748 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1750 if(dirty.bit.cone_orient)
1751 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1752 params->vConeOrientation.y,
1753 -params->vConeOrientation.z);
1754 if(dirty.bit.cone_outsidevolume)
1755 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1756 if(dirty.bit.min_distance)
1757 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1758 if(dirty.bit.max_distance)
1759 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1760 if(dirty.bit.mode)
1762 This->ds3dmode = params->dwMode;
1763 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1764 AL_TRUE : AL_FALSE);
1765 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1766 0.0f : This->primary->rollofffactor);
1770 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1772 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1773 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1776 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1778 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1779 LONG ret;
1781 InterlockedIncrement(&This->all_ref);
1782 ret = InterlockedIncrement(&This->ds3d_ref);
1783 TRACE("new refcount %ld\n", ret);
1785 return ret;
1788 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1790 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1791 LONG ret;
1793 ret = InterlockedDecrement(&This->ds3d_ref);
1794 TRACE("new refcount %ld\n", ret);
1795 if(InterlockedDecrement(&This->all_ref) == 0)
1796 DS8Buffer_Destroy(This);
1798 return ret;
1801 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1803 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1804 ALint inangle, outangle;
1806 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1807 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1809 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1810 return DSERR_INVALIDPARAM;
1813 EnterCriticalSection(This->crst);
1814 setALContext(This->ctx);
1816 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1817 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1818 checkALError();
1820 popALContext();
1821 LeaveCriticalSection(This->crst);
1823 *pdwInsideConeAngle = inangle;
1824 *pdwOutsideConeAngle = outangle;
1825 return S_OK;
1828 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1830 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1831 ALfloat dir[3];
1833 TRACE("(%p)->(%p)\n", This, orient);
1834 if(!orient)
1836 WARN("Invalid pointer\n");
1837 return DSERR_INVALIDPARAM;
1840 setALContext(This->ctx);
1841 alGetSourcefv(This->source, AL_DIRECTION, dir);
1842 checkALError();
1843 popALContext();
1845 orient->x = dir[0];
1846 orient->y = dir[1];
1847 orient->z = -dir[2];
1848 return S_OK;
1851 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1853 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1854 ALfloat gain;
1856 TRACE("(%p)->(%p)\n", This, vol);
1857 if(!vol)
1859 WARN("Invalid pointer\n");
1860 return DSERR_INVALIDPARAM;
1863 setALContext(This->ctx);
1864 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1865 checkALError();
1866 popALContext();
1868 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1869 return S_OK;
1872 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1874 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1875 ALfloat dist;
1877 TRACE("(%p)->(%p)\n", This, maxdist);
1878 if(!maxdist)
1880 WARN("Invalid pointer\n");
1881 return DSERR_INVALIDPARAM;
1884 setALContext(This->ctx);
1885 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1886 checkALError();
1887 popALContext();
1889 *maxdist = dist;
1890 return S_OK;
1893 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1895 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1896 ALfloat dist;
1898 TRACE("(%p)->(%p)\n", This, mindist);
1899 if(!mindist)
1901 WARN("Invalid pointer\n");
1902 return DSERR_INVALIDPARAM;
1905 setALContext(This->ctx);
1906 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1907 checkALError();
1908 popALContext();
1910 *mindist = dist;
1911 return S_OK;
1914 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1916 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1918 TRACE("(%p)->(%p)\n", This, mode);
1919 if(!mode)
1921 WARN("Invalid pointer\n");
1922 return DSERR_INVALIDPARAM;
1925 EnterCriticalSection(This->crst);
1926 *mode = This->ds3dmode;
1927 LeaveCriticalSection(This->crst);
1929 return S_OK;
1932 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1934 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1935 ALfloat alpos[3];
1937 TRACE("(%p)->(%p)\n", This, pos);
1938 if(!pos)
1940 WARN("Invalid pointer\n");
1941 return DSERR_INVALIDPARAM;
1944 setALContext(This->ctx);
1945 alGetSourcefv(This->source, AL_POSITION, alpos);
1946 checkALError();
1947 popALContext();
1949 pos->x = alpos[0];
1950 pos->y = alpos[1];
1951 pos->z = -alpos[2];
1952 return S_OK;
1955 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1957 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1958 ALfloat alvel[3];
1960 TRACE("(%p)->(%p)\n", This, vel);
1961 if(!vel)
1963 WARN("Invalid pointer\n");
1964 return DSERR_INVALIDPARAM;
1967 setALContext(This->ctx);
1968 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1969 checkALError();
1970 popALContext();
1972 vel->x = alvel[0];
1973 vel->y = alvel[1];
1974 vel->z = -alvel[2];
1975 return S_OK;
1978 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1980 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1982 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1984 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1986 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1987 return DSERR_INVALIDPARAM;
1990 EnterCriticalSection(This->crst);
1991 setALContext(This->ctx);
1993 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1994 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1995 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1996 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1997 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1998 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1999 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
2000 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
2002 popALContext();
2003 LeaveCriticalSection(This->crst);
2005 return DS_OK;
2008 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2010 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2012 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2013 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2014 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2016 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
2017 return DSERR_INVALIDPARAM;
2020 EnterCriticalSection(This->crst);
2021 if(apply == DS3D_DEFERRED)
2023 This->params.dwInsideConeAngle = dwInsideConeAngle;
2024 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
2025 This->dirty.bit.cone_angles = 1;
2027 else
2029 setALContext(This->ctx);
2030 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2031 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2032 checkALError();
2033 popALContext();
2035 LeaveCriticalSection(This->crst);
2037 return S_OK;
2040 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2042 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2044 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2046 if(apply == DS3D_DEFERRED)
2048 EnterCriticalSection(This->crst);
2049 This->params.vConeOrientation.x = x;
2050 This->params.vConeOrientation.y = y;
2051 This->params.vConeOrientation.z = z;
2052 This->dirty.bit.cone_orient = 1;
2053 LeaveCriticalSection(This->crst);
2055 else
2057 setALContext(This->ctx);
2058 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2059 checkALError();
2060 popALContext();
2063 return S_OK;
2066 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2068 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2070 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
2071 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2073 WARN("Invalid volume (%ld)\n", vol);
2074 return DSERR_INVALIDPARAM;
2077 if(apply == DS3D_DEFERRED)
2079 EnterCriticalSection(This->crst);
2080 This->params.lConeOutsideVolume = vol;
2081 This->dirty.bit.cone_outsidevolume = 1;
2082 LeaveCriticalSection(This->crst);
2084 else
2086 setALContext(This->ctx);
2087 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2088 checkALError();
2089 popALContext();
2092 return S_OK;
2095 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2097 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2099 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2100 if(maxdist < 0.0f)
2102 WARN("Invalid max distance (%f)\n", maxdist);
2103 return DSERR_INVALIDPARAM;
2106 if(apply == DS3D_DEFERRED)
2108 EnterCriticalSection(This->crst);
2109 This->params.flMaxDistance = maxdist;
2110 This->dirty.bit.max_distance = 1;
2111 LeaveCriticalSection(This->crst);
2113 else
2115 setALContext(This->ctx);
2116 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2117 checkALError();
2118 popALContext();
2121 return S_OK;
2124 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2126 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2128 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2129 if(mindist < 0.0f)
2131 WARN("Invalid min distance (%f)\n", mindist);
2132 return DSERR_INVALIDPARAM;
2135 if(apply == DS3D_DEFERRED)
2137 EnterCriticalSection(This->crst);
2138 This->params.flMinDistance = mindist;
2139 This->dirty.bit.min_distance = 1;
2140 LeaveCriticalSection(This->crst);
2142 else
2144 setALContext(This->ctx);
2145 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2146 checkALError();
2147 popALContext();
2150 return S_OK;
2153 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2155 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2157 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2158 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2159 mode != DS3DMODE_DISABLE)
2161 WARN("Invalid mode (%lu)\n", mode);
2162 return DSERR_INVALIDPARAM;
2165 EnterCriticalSection(This->crst);
2166 if(apply == DS3D_DEFERRED)
2168 This->params.dwMode = mode;
2169 This->dirty.bit.mode = 1;
2171 else
2173 setALContext(This->ctx);
2174 alSourcei(This->source, AL_SOURCE_RELATIVE,
2175 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2176 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2177 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2178 This->ds3dmode = mode;
2179 checkALError();
2180 popALContext();
2182 LeaveCriticalSection(This->crst);
2184 return S_OK;
2187 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2189 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2191 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2193 if(apply == DS3D_DEFERRED)
2195 EnterCriticalSection(This->crst);
2196 This->params.vPosition.x = x;
2197 This->params.vPosition.y = y;
2198 This->params.vPosition.z = z;
2199 This->dirty.bit.pos = 1;
2200 LeaveCriticalSection(This->crst);
2202 else
2204 setALContext(This->ctx);
2205 alSource3f(This->source, AL_POSITION, x, y, -z);
2206 checkALError();
2207 popALContext();
2210 return S_OK;
2213 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2215 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2217 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2219 if(apply == DS3D_DEFERRED)
2221 EnterCriticalSection(This->crst);
2222 This->params.vVelocity.x = x;
2223 This->params.vVelocity.y = y;
2224 This->params.vVelocity.z = z;
2225 This->dirty.bit.vel = 1;
2226 LeaveCriticalSection(This->crst);
2228 else
2230 setALContext(This->ctx);
2231 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2232 checkALError();
2233 popALContext();
2236 return S_OK;
2239 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2241 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2242 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2244 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2246 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2247 return DSERR_INVALIDPARAM;
2250 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2251 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2253 WARN("Invalid cone angles (%lu, %lu)\n",
2254 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2255 return DSERR_INVALIDPARAM;
2258 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2259 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2261 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2262 return DSERR_INVALIDPARAM;
2265 if(ds3dbuffer->flMaxDistance < 0.0f)
2267 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2268 return DSERR_INVALIDPARAM;
2271 if(ds3dbuffer->flMinDistance < 0.0f)
2273 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2274 return DSERR_INVALIDPARAM;
2277 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2278 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2279 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2281 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2282 return DSERR_INVALIDPARAM;
2285 if(apply == DS3D_DEFERRED)
2287 EnterCriticalSection(This->crst);
2288 This->params = *ds3dbuffer;
2289 This->params.dwSize = sizeof(This->params);
2290 This->dirty.bit.pos = 1;
2291 This->dirty.bit.vel = 1;
2292 This->dirty.bit.cone_angles = 1;
2293 This->dirty.bit.cone_orient = 1;
2294 This->dirty.bit.cone_outsidevolume = 1;
2295 This->dirty.bit.min_distance = 1;
2296 This->dirty.bit.max_distance = 1;
2297 This->dirty.bit.mode = 1;
2298 LeaveCriticalSection(This->crst);
2300 else
2302 union BufferParamFlags dirty = { 0 };
2303 dirty.bit.pos = 1;
2304 dirty.bit.vel = 1;
2305 dirty.bit.cone_angles = 1;
2306 dirty.bit.cone_orient = 1;
2307 dirty.bit.cone_outsidevolume = 1;
2308 dirty.bit.min_distance = 1;
2309 dirty.bit.max_distance = 1;
2310 dirty.bit.mode = 1;
2312 EnterCriticalSection(This->crst);
2313 setALContext(This->ctx);
2314 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
2315 checkALError();
2316 popALContext();
2317 LeaveCriticalSection(This->crst);
2320 return S_OK;
2323 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2325 DS8Buffer3D_QueryInterface,
2326 DS8Buffer3D_AddRef,
2327 DS8Buffer3D_Release,
2328 DS8Buffer3D_GetAllParameters,
2329 DS8Buffer3D_GetConeAngles,
2330 DS8Buffer3D_GetConeOrientation,
2331 DS8Buffer3D_GetConeOutsideVolume,
2332 DS8Buffer3D_GetMaxDistance,
2333 DS8Buffer3D_GetMinDistance,
2334 DS8Buffer3D_GetMode,
2335 DS8Buffer3D_GetPosition,
2336 DS8Buffer3D_GetVelocity,
2337 DS8Buffer3D_SetAllParameters,
2338 DS8Buffer3D_SetConeAngles,
2339 DS8Buffer3D_SetConeOrientation,
2340 DS8Buffer3D_SetConeOutsideVolume,
2341 DS8Buffer3D_SetMaxDistance,
2342 DS8Buffer3D_SetMinDistance,
2343 DS8Buffer3D_SetMode,
2344 DS8Buffer3D_SetPosition,
2345 DS8Buffer3D_SetVelocity
2349 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2351 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2352 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2355 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2357 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2358 LONG ret;
2360 InterlockedIncrement(&This->all_ref);
2361 ret = InterlockedIncrement(&This->not_ref);
2362 TRACE("new refcount %ld\n", ret);
2364 return ret;
2367 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2369 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2370 LONG ret;
2372 ret = InterlockedDecrement(&This->not_ref);
2373 TRACE("new refcount %ld\n", ret);
2374 if(InterlockedDecrement(&This->all_ref) == 0)
2375 DS8Buffer_Destroy(This);
2377 return ret;
2380 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2382 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2383 DSBPOSITIONNOTIFY *nots;
2384 DWORD state;
2385 HRESULT hr;
2387 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2389 EnterCriticalSection(This->crst);
2390 hr = DSERR_INVALIDPARAM;
2391 if(count && !notifications)
2392 goto out;
2394 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2395 if(FAILED(hr)) goto out;
2397 hr = DSERR_INVALIDCALL;
2398 if((state&DSBSTATUS_PLAYING))
2399 goto out;
2401 if(!count)
2403 HeapFree(GetProcessHeap(), 0, This->notify);
2404 This->notify = 0;
2405 This->nnotify = 0;
2406 hr = S_OK;
2408 else
2410 DWORD i;
2412 hr = DSERR_INVALIDPARAM;
2413 for(i = 0;i < count;++i)
2415 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2416 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2417 goto out;
2420 hr = E_OUTOFMEMORY;
2421 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2422 if(!nots) goto out;
2423 memcpy(nots, notifications, count*sizeof(*nots));
2425 HeapFree(GetProcessHeap(), 0, This->notify);
2426 This->notify = nots;
2427 This->nnotify = count;
2429 hr = S_OK;
2432 out:
2433 LeaveCriticalSection(This->crst);
2434 return hr;
2437 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2439 DS8BufferNot_QueryInterface,
2440 DS8BufferNot_AddRef,
2441 DS8BufferNot_Release,
2442 DS8BufferNot_SetNotificationPositions
2446 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2448 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2449 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2452 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2454 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2455 LONG ret;
2457 InterlockedIncrement(&This->all_ref);
2458 ret = InterlockedIncrement(&This->prop_ref);
2459 TRACE("new refcount %ld\n", ret);
2461 return ret;
2464 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2466 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2467 LONG ret;
2469 ret = InterlockedDecrement(&This->prop_ref);
2470 TRACE("new refcount %ld\n", ret);
2471 if(InterlockedDecrement(&This->all_ref) == 0)
2472 DS8Buffer_Destroy(This);
2474 return ret;
2477 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2478 handled through secondary buffers. */
2479 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2480 REFGUID guidPropSet, ULONG dwPropID,
2481 LPVOID pInstanceData, ULONG cbInstanceData,
2482 LPVOID pPropData, ULONG cbPropData,
2483 ULONG *pcbReturned)
2485 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2486 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2488 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2489 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2491 if(!pcbReturned)
2492 return E_POINTER;
2493 *pcbReturned = 0;
2495 #if 0
2496 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2499 else
2500 #endif
2501 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2503 DS8Primary *prim = This->primary;
2505 EnterCriticalSection(This->crst);
2507 hr = DSERR_INVALIDPARAM;
2508 if(prim->effect == 0)
2509 hr = E_PROP_ID_UNSUPPORTED;
2510 else switch(dwPropID)
2512 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2513 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
2515 union {
2516 void *v;
2517 EAXLISTENERPROPERTIES *props;
2518 } data = { pPropData };
2520 *data.props = prim->eax_prop;
2521 *pcbReturned = sizeof(EAXLISTENERPROPERTIES);
2522 hr = DS_OK;
2524 break;
2526 case DSPROPERTY_EAXLISTENER_ROOM:
2527 if(cbPropData >= sizeof(LONG))
2529 union {
2530 void *v;
2531 LONG *l;
2532 } data = { pPropData };
2534 *data.l = prim->eax_prop.lRoom;
2535 *pcbReturned = sizeof(LONG);
2536 hr = DS_OK;
2538 break;
2539 case DSPROPERTY_EAXLISTENER_ROOMHF:
2540 if(cbPropData >= sizeof(LONG))
2542 union {
2543 void *v;
2544 LONG *l;
2545 } data = { pPropData };
2547 *data.l = prim->eax_prop.lRoomHF;
2548 *pcbReturned = sizeof(LONG);
2549 hr = DS_OK;
2551 break;
2553 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2554 if(cbPropData >= sizeof(FLOAT))
2556 union {
2557 void *v;
2558 FLOAT *fl;
2559 } data = { pPropData };
2561 *data.fl = prim->eax_prop.flRoomRolloffFactor;
2562 *pcbReturned = sizeof(FLOAT);
2563 hr = DS_OK;
2565 break;
2567 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2568 if(cbPropData >= sizeof(DWORD))
2570 union {
2571 void *v;
2572 DWORD *dw;
2573 } data = { pPropData };
2575 *data.dw = prim->eax_prop.dwEnvironment;
2576 *pcbReturned = sizeof(DWORD);
2577 hr = DS_OK;
2579 break;
2581 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2582 if(cbPropData >= sizeof(FLOAT))
2584 union {
2585 void *v;
2586 FLOAT *fl;
2587 } data = { pPropData };
2589 *data.fl = prim->eax_prop.flEnvironmentSize;
2590 *pcbReturned = sizeof(FLOAT);
2591 hr = DS_OK;
2593 break;
2594 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2595 if(cbPropData >= sizeof(FLOAT))
2597 union {
2598 void *v;
2599 FLOAT *fl;
2600 } data = { pPropData };
2602 *data.fl = prim->eax_prop.flEnvironmentDiffusion;
2603 *pcbReturned = sizeof(FLOAT);
2604 hr = DS_OK;
2606 break;
2608 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2609 if(cbPropData >= sizeof(FLOAT))
2611 union {
2612 void *v;
2613 FLOAT *fl;
2614 } data = { pPropData };
2616 *data.fl = prim->eax_prop.flAirAbsorptionHF;
2617 *pcbReturned = sizeof(FLOAT);
2618 hr = DS_OK;
2620 break;
2622 case DSPROPERTY_EAXLISTENER_FLAGS:
2623 if(cbPropData >= sizeof(DWORD))
2625 union {
2626 void *v;
2627 DWORD *dw;
2628 } data = { pPropData };
2630 *data.dw = prim->eax_prop.dwFlags;
2631 *pcbReturned = sizeof(DWORD);
2632 hr = DS_OK;
2634 break;
2636 default:
2637 hr = E_PROP_ID_UNSUPPORTED;
2638 FIXME("Unhandled propid: 0x%08lx\n", dwPropID);
2639 break;
2642 LeaveCriticalSection(This->crst);
2644 else
2645 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2647 return hr;
2650 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2651 REFGUID guidPropSet, ULONG dwPropID,
2652 LPVOID pInstanceData, ULONG cbInstanceData,
2653 LPVOID pPropData, ULONG cbPropData)
2655 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2656 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2658 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2659 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2661 #if 0
2662 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2665 else
2666 #endif
2667 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2669 DS8Primary *prim = This->primary;
2670 DWORD propid = dwPropID & ~DSPROPERTY_EAXLISTENER_DEFERRED;
2671 BOOL immediate = !(dwPropID&DSPROPERTY_EAXLISTENER_DEFERRED);
2673 EnterCriticalSection(prim->crst);
2674 setALContext(prim->ctx);
2676 hr = DSERR_INVALIDPARAM;
2677 if(prim->effect == 0)
2678 hr = E_PROP_ID_UNSUPPORTED;
2679 else switch(propid)
2681 case DSPROPERTY_EAXLISTENER_NONE: /* not setting any property, just applying */
2682 hr = DS_OK;
2683 break;
2685 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS:
2686 do_allparams:
2687 if(cbPropData >= sizeof(EAXLISTENERPROPERTIES))
2689 union {
2690 const void *v;
2691 const EAXLISTENERPROPERTIES *props;
2692 } data = { pPropData };
2694 /* FIXME: Need to validate property values... Ignore? Clamp? Error? */
2695 prim->eax_prop = *data.props;
2696 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DENSITY,
2697 clampF(powf(data.props->flEnvironmentSize, 3.0f) / 16.0f,
2698 0.0f, 1.0f)
2700 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
2701 data.props->flEnvironmentDiffusion);
2703 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2704 mB_to_gain(data.props->lRoom));
2705 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2706 mB_to_gain(data.props->lRoomHF));
2708 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2709 data.props->flRoomRolloffFactor);
2711 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_TIME,
2712 data.props->flDecayTime);
2713 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DECAY_HFRATIO,
2714 data.props->flDecayHFRatio);
2716 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_GAIN,
2717 mB_to_gain(data.props->lReflections));
2718 prim->ExtAL->Effectf(prim->effect, AL_REVERB_REFLECTIONS_DELAY,
2719 data.props->flReflectionsDelay);
2721 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_GAIN,
2722 mB_to_gain(data.props->lReverb));
2723 prim->ExtAL->Effectf(prim->effect, AL_REVERB_LATE_REVERB_DELAY,
2724 data.props->flReverbDelay);
2726 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2727 mBF_to_gain(data.props->flAirAbsorptionHF));
2729 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2730 (data.props->dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2731 AL_TRUE : AL_FALSE);
2733 checkALError();
2735 prim->dirty.bit.effect = 1;
2736 hr = DS_OK;
2738 break;
2740 case DSPROPERTY_EAXLISTENER_ROOM:
2741 if(cbPropData >= sizeof(LONG))
2743 union {
2744 const void *v;
2745 const LONG *l;
2746 } data = { pPropData };
2748 prim->eax_prop.lRoom = *data.l;
2749 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAIN,
2750 mB_to_gain(prim->eax_prop.lRoom));
2751 checkALError();
2753 prim->dirty.bit.effect = 1;
2754 hr = DS_OK;
2756 break;
2757 case DSPROPERTY_EAXLISTENER_ROOMHF:
2758 if(cbPropData >= sizeof(LONG))
2760 union {
2761 const void *v;
2762 const LONG *l;
2763 } data = { pPropData };
2765 prim->eax_prop.lRoomHF = *data.l;
2766 prim->ExtAL->Effectf(prim->effect, AL_REVERB_GAINHF,
2767 mB_to_gain(prim->eax_prop.lRoomHF));
2768 checkALError();
2770 prim->dirty.bit.effect = 1;
2771 hr = DS_OK;
2773 break;
2775 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR:
2776 if(cbPropData >= sizeof(FLOAT))
2778 union {
2779 const void *v;
2780 const FLOAT *fl;
2781 } data = { pPropData };
2783 prim->eax_prop.flRoomRolloffFactor = *data.fl;
2784 prim->ExtAL->Effectf(prim->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR,
2785 prim->eax_prop.flRoomRolloffFactor);
2786 checkALError();
2788 prim->dirty.bit.effect = 1;
2789 hr = DS_OK;
2791 break;
2793 case DSPROPERTY_EAXLISTENER_ENVIRONMENT:
2794 if(cbPropData >= sizeof(DWORD))
2796 union {
2797 const void *v;
2798 const DWORD *dw;
2799 } data = { pPropData };
2801 if(*data.dw <= EAX_MAX_ENVIRONMENT)
2803 /* Get the environment index's default and pass it down to
2804 * ALLPARAMETERS */
2805 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2806 pPropData = (void*)&EnvironmentDefaults[*data.dw];
2807 cbPropData = sizeof(EnvironmentDefaults[*data.dw]);
2808 goto do_allparams;
2811 break;
2813 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE:
2814 if(cbPropData >= sizeof(FLOAT))
2816 union {
2817 const void *v;
2818 const FLOAT *fl;
2819 } data = { pPropData };
2821 if(*data.fl >= 1.0f && *data.fl <= 100.0f)
2823 float scale = (*data.fl)/prim->eax_prop.flEnvironmentSize;
2825 prim->eax_prop.flEnvironmentSize = *data.fl;
2827 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYTIMESCALE))
2829 prim->eax_prop.flDecayTime *= scale;
2830 prim->eax_prop.flDecayTime = clampF(prim->eax_prop.flDecayTime, 0.1f, 20.0f);
2832 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSSCALE))
2834 prim->eax_prop.lReflections -= gain_to_mB(scale);
2835 prim->eax_prop.lReflections = clampI(prim->eax_prop.lReflections, -10000, 1000);
2837 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE))
2839 prim->eax_prop.flReflectionsDelay *= scale;
2840 prim->eax_prop.flReflectionsDelay = clampF(prim->eax_prop.flReflectionsDelay, 0.0f, 0.3f);
2842 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBSCALE))
2844 prim->eax_prop.lReverb -= gain_to_mB(scale);
2845 prim->eax_prop.lReverb = clampI(prim->eax_prop.lReverb, -10000, 2000);
2847 if((prim->eax_prop.dwFlags&EAXLISTENERFLAGS_REVERBDELAYSCALE))
2849 prim->eax_prop.flReverbDelay *= scale;
2850 prim->eax_prop.flReverbDelay = clampF(prim->eax_prop.flReverbDelay, 0.0f, 0.1f);
2853 /* Pass the updated environment properties down to ALLPARAMETERS */
2854 propid = DSPROPERTY_EAXLISTENER_ALLPARAMETERS;
2855 pPropData = (void*)&prim->eax_prop;
2856 cbPropData = sizeof(prim->eax_prop);
2857 goto do_allparams;
2860 break;
2861 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION:
2862 if(cbPropData >= sizeof(FLOAT))
2864 union {
2865 const void *v;
2866 const FLOAT *fl;
2867 } data = { pPropData };
2869 prim->eax_prop.flEnvironmentDiffusion = *data.fl;
2870 prim->ExtAL->Effectf(prim->effect, AL_REVERB_DIFFUSION,
2871 prim->eax_prop.flEnvironmentDiffusion);
2872 checkALError();
2874 prim->dirty.bit.effect = 1;
2875 hr = DS_OK;
2877 break;
2879 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF:
2880 if(cbPropData >= sizeof(FLOAT))
2882 union {
2883 const void *v;
2884 const FLOAT *fl;
2885 } data = { pPropData };
2887 prim->eax_prop.flAirAbsorptionHF = *data.fl;
2888 prim->ExtAL->Effectf(prim->effect, AL_REVERB_AIR_ABSORPTION_GAINHF,
2889 mBF_to_gain(prim->eax_prop.flAirAbsorptionHF));
2890 checkALError();
2892 prim->dirty.bit.effect = 1;
2893 hr = DS_OK;
2895 break;
2897 case DSPROPERTY_EAXLISTENER_FLAGS:
2898 if(cbPropData >= sizeof(DWORD))
2900 union {
2901 const void *v;
2902 const DWORD *dw;
2903 } data = { pPropData };
2905 prim->eax_prop.dwFlags = *data.dw;
2906 prim->ExtAL->Effecti(prim->effect, AL_REVERB_DECAY_HFLIMIT,
2907 (prim->eax_prop.dwFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ?
2908 AL_TRUE : AL_FALSE);
2909 checkALError();
2911 prim->dirty.bit.effect = 1;
2912 hr = DS_OK;
2914 break;
2916 default:
2917 hr = E_PROP_ID_UNSUPPORTED;
2918 FIXME("Unhandled propid: 0x%08lx\n", propid);
2919 break;
2922 if(hr == DS_OK && immediate)
2923 DS8Primary3D_CommitDeferredSettings(&prim->IDirectSound3DListener_iface);
2925 popALContext();
2926 LeaveCriticalSection(prim->crst);
2928 else
2929 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2931 return hr;
2934 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2935 REFGUID guidPropSet, ULONG dwPropID,
2936 ULONG *pTypeSupport)
2938 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2939 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2941 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2943 if(!pTypeSupport)
2944 return E_POINTER;
2945 *pTypeSupport = 0;
2947 #if 0
2948 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2951 else
2952 #endif
2953 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_ListenerProperties))
2955 DS8Primary *prim = This->primary;
2957 EnterCriticalSection(This->crst);
2959 if(prim->effect == 0)
2960 hr = E_PROP_ID_UNSUPPORTED;
2961 else if(dwPropID == DSPROPERTY_EAXLISTENER_ALLPARAMETERS ||
2962 dwPropID == DSPROPERTY_EAXLISTENER_ROOM ||
2963 dwPropID == DSPROPERTY_EAXLISTENER_ROOMHF ||
2964 dwPropID == DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR ||
2965 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENT ||
2966 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE ||
2967 dwPropID == DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION ||
2968 dwPropID == DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF ||
2969 dwPropID == DSPROPERTY_EAXLISTENER_FLAGS)
2971 *pTypeSupport = KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET;
2972 hr = DS_OK;
2974 else
2975 FIXME("Unhandled propid: 0x%08lx\n", dwPropID);
2977 LeaveCriticalSection(This->crst);
2979 else
2980 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet));
2982 return hr;
2985 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2987 DS8BufferProp_QueryInterface,
2988 DS8BufferProp_AddRef,
2989 DS8BufferProp_Release,
2990 DS8BufferProp_Get,
2991 DS8BufferProp_Set,
2992 DS8BufferProp_QuerySupport