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
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);
47 #define DS_INCOMPLETE ((HRESULT)0x08780020)
50 #ifndef WAVE_FORMAT_IEEE_FLOAT
51 #define WAVE_FORMAT_IEEE_FLOAT 3
55 /* TODO: when bufferlost is set, return from all calls except initialize with
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
;
97 list
= prim
->notifies
;
98 for(i
= 0; i
< prim
->nnotifies
; ++i
)
102 ERR("Buffer %p already in notification list\n", buf
);
106 if(prim
->nnotifies
== prim
->sizenotifies
)
108 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (prim
->nnotifies
+ 1) * sizeof(*list
));
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");
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
);
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");
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
);
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
);
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
);
216 if(out
->dwChannelMask
!= MONO
&& out
->dwChannelMask
!= STEREO
&&
217 !prim
->SupportedExt
[EXT_MCFORMATS
])
219 WARN("Multi-channel not available\n");
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
);
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";
274 WARN("Invalid float bits: %u\n", out
->Samples
.wValidBitsPerSample
);
278 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
279 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
282 else if(!IsEqualGUID(&out
->SubFormat
, &GUID_NULL
))
283 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out
->SubFormat
));
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
;
296 format
= desc
->lpwfxFormat
;
297 TRACE("Requested buffer format:\n"
298 " FormatTag = 0x%04x\n"
300 " SamplesPerSec = %lu\n"
301 " AvgBytesPerSec = %lu\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
);
360 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
361 if(!pBuffer
) return E_OUTOFMEMORY
;
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
))
382 wfe
= CONTAINING_RECORD(format
, const WAVEFORMATEXTENSIBLE
, Format
);
383 TRACE("Extensible values:\n"
385 " ChannelMask = 0x%lx\n"
387 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
388 debugstr_guid(&wfe
->SubFormat
));
390 fmt_str
= get_fmtstr_EXT(prim
, format
, &pBuffer
->format
);
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
);
405 if(!prim
->SupportedExt
[SOFTX_MAP_BUFFER
])
407 pBuffer
->data
= (BYTE
*)(pBuffer
+1);
409 alGenBuffers(1, &pBuffer
->bid
);
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
);
422 if(!pBuffer
->data
) goto fail
;
429 DS8Data_Release(pBuffer
);
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
);
446 DS8Primary
*prim
= This
->primary
;
447 if(prim
->SupportedExt
[SOFTX_MAP_BUFFER
])
448 prim
->ExtAL
->UnmapBufferSOFT(This
->bid
);
449 alDeleteBuffers(1, &This
->bid
);
452 HeapFree(GetProcessHeap(), 0, This
);
456 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*prim
, IDirectSoundBuffer
*orig
, BOOL prim_emu
)
458 DS8Buffer
*This
= NULL
;
463 EnterCriticalSection(prim
->crst
);
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
);
480 LeaveCriticalSection(prim
->crst
);
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;
500 DS8Buffer
*org
= impl_from_IDirectSoundBuffer(orig
);
501 hr
= DSERR_BUFFERLOST
;
504 DS8Data_AddRef(org
->buffer
);
505 This
->buffer
= org
->buffer
;
508 /* Disable until initialized.. */
509 This
->ds3dmode
= DS3DMODE_DISABLE
;
515 DS8Buffer_Destroy(This
);
519 void DS8Buffer_Destroy(DS8Buffer
*This
)
521 DS8Primary
*prim
= This
->primary
;
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
];
538 setALContext(This
->ctx
);
541 alSourceStop(This
->source
);
542 alSourcei(This
->source
, AL_BUFFER
, 0);
545 prim
->sources
[prim
->parent
->share
->nsources
++] = This
->source
;
548 if(This
->stream_bids
[0])
549 alDeleteBuffers(QBUFFERS
, This
->stream_bids
);
552 DS8Data_Release(This
->buffer
);
556 HeapFree(GetProcessHeap(), 0, This
->notify
);
558 for(i
= 0;i
< prim
->NumBufferGroups
;++i
)
560 DWORD_PTR idx
= This
- prim
->BufferGroups
[i
].Buffers
;
563 prim
->BufferGroups
[i
].FreeBuffers
|= U64(1) << idx
;
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
);
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
;
601 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
605 IUnknown_AddRef((IUnknown
*)*ppv
);
609 return E_NOINTERFACE
;
612 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
614 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
617 InterlockedIncrement(&This
->all_ref
);
618 ret
= InterlockedIncrement(&This
->ref
);
619 TRACE("new refcount %ld\n", ret
);
624 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
626 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
629 ret
= InterlockedDecrement(&This
->ref
);
630 TRACE("new refcount %ld\n", ret
);
631 if(InterlockedDecrement(&This
->all_ref
) == 0)
632 DS8Buffer_Destroy(This
);
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;
656 HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
658 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
659 ALsizei writecursor
, pos
;
662 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
665 if(This
->segsize
!= 0)
667 ALint queued
= QBUFFERS
;
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
);
680 if(status
== AL_STOPPED
)
681 pos
= This
->segsize
*queued
+ This
->queue_base
;
683 pos
= ofs
+ This
->queue_base
;
684 if(pos
>= data
->buf_size
)
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);
694 This
->isplaying
= FALSE
;
698 writecursor
= (This
->segsize
*QBUFFERS
+ pos
) % data
->buf_size
;
700 writecursor
= pos
% data
->buf_size
;
702 LeaveCriticalSection(This
->crst
);
706 const WAVEFORMATEX
*format
= &data
->format
.Format
;
710 setALContext(This
->ctx
);
711 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
712 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
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
;
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
;
750 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
752 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
756 TRACE("(%p)->(%p, %lu, %p)\n", iface
, wfx
, allocated
, 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
;
768 hr
= DSERR_INVALIDPARAM
;
770 memcpy(wfx
, &This
->buffer
->format
.Format
, size
);
778 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
780 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
783 TRACE("(%p)->(%p)\n", iface
, 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");
798 setALContext(This
->ctx
);
799 alGetSourcef(This
->source
, AL_GAIN
, &gain
);
803 *vol
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
810 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
812 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
815 TRACE("(%p)->(%p)\n", iface
, 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");
828 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
834 setALContext(This
->ctx
);
835 alGetSourcefv(This
->source
, AL_POSITION
, pos
);
839 *pan
= clampI((LONG
)((pos
[0]+0.5f
)*(DSBPAN_RIGHT
-DSBPAN_LEFT
) + 0.5f
) + DSBPAN_LEFT
,
840 DSBPAN_LEFT
, DSBPAN_RIGHT
);
848 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
850 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
853 TRACE("(%p)->(%p)\n", iface
, 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");
866 ALfloat pitch
= 1.0f
;
868 setALContext(This
->ctx
);
869 alGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
873 *freq
= (DWORD
)(This
->buffer
->format
.Format
.nSamplesPerSec
* pitch
);
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
);
889 WARN("Invalid pointer\n");
890 return DSERR_INVALIDPARAM
;
894 if(This
->segsize
== 0)
896 setALContext(This
->ctx
);
897 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
898 alGetSourcei(This
->source
, AL_LOOPING
, &looping
);
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
);
924 HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
926 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
927 DS3DBUFFER
*ds3dbuffer
;
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
;
942 hr
= DSERR_INVALIDPARAM
;
945 WARN("Missing DSound buffer description\n");
948 if(!desc
->lpwfxFormat
)
950 WARN("Missing buffer format (%p)\n", This
);
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
959 WARN("Can't create multi-channel 3D buffers\n");
966 ERR("Multi-channel 3D sounds are not spatialized\n");
969 if((desc
->dwFlags
&DSBCAPS_CTRLPAN
) && desc
->lpwfxFormat
->nChannels
!= 1)
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
;
980 if(data
->format
.Format
.wBitsPerSample
== 8)
981 memset(data
->data
, 0x80, data
->buf_size
);
983 memset(data
->data
, 0x00, data
->buf_size
);
986 prim
= This
->primary
;
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
);
999 hr
= DSERR_ALLOCATED
;
1000 if(!prim
->parent
->share
->nsources
)
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
);
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
);
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;
1042 DS8Buffer_SetParams(This
, ds3dbuffer
, dirty
.flags
);
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
);
1074 LeaveCriticalSection(This
->crst
);
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
);
1084 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1088 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1089 return DSERR_INVALIDPARAM
;
1094 if(ptr2
) *ptr2
= NULL
;
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
;
1130 if(ptr2
&& len2
&& remain
)
1132 *ptr2
= This
->buffer
->data
;
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
;
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
);
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
;
1166 data
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1171 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This
->buffer
, prio
);
1172 hr
= DSERR_INVALIDPARAM
;
1176 if(This
->segsize
!= 0)
1178 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1179 if(This
->isplaying
) state
= AL_PLAYING
;
1183 alSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1184 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1189 if(state
== AL_PLAYING
)
1192 if(This
->segsize
== 0)
1194 if(state
!= AL_PAUSED
)
1195 alSourcei(This
->source
, AL_BUFFER
, data
->bid
);
1196 alSourcePlay(This
->source
);
1200 alSourceRewind(This
->source
);
1201 alSourcei(This
->source
, AL_BUFFER
, 0);
1202 This
->queue_base
= This
->data_offset
% data
->buf_size
;
1205 if(alGetError() != AL_NO_ERROR
)
1207 ERR("Couldn't start source\n");
1208 alSourcei(This
->source
, AL_BUFFER
, 0);
1213 This
->isplaying
= TRUE
;
1214 This
->playflags
= flags
;
1217 DS8Buffer_addnotify(This
);
1221 LeaveCriticalSection(This
->crst
);
1225 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1227 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
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)
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);
1251 This
->queue_base
= This
->data_offset
= pos
;
1256 setALContext(This
->ctx
);
1257 alSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1260 This
->lastpos
= pos
;
1262 LeaveCriticalSection(This
->crst
);
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
);
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
;
1290 ALfloat fvol
= mB_to_gain(vol
);
1291 setALContext(This
->ctx
);
1292 alSourcef(This
->source
, AL_GAIN
, fvol
);
1299 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1301 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
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
;
1316 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
1319 pos
[0] = (ALfloat
)(pan
-DSBPAN_LEFT
)/(ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 0.5f
;
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
1325 pos
[2] = -sqrtf(1.0f
- pos
[0]*pos
[0]);
1327 setALContext(This
->ctx
);
1328 alSourcefv(This
->source
, AL_POSITION
, pos
);
1337 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1339 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
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
;
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
);
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
);
1379 This
->isplaying
= FALSE
;
1380 DS8Primary_triggernots(This
->primary
);
1383 LeaveCriticalSection(This
->crst
);
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
;
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
))
1413 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1422 if(This
->primary
->SupportedExt
[SOFTX_MAP_BUFFER
])
1424 setALContext(This
->ctx
);
1425 This
->ExtAL
->FlushMappedBufferSOFT(buf
->bid
, 0, buf
->buf_size
);
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
);
1440 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1444 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1446 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
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;
1459 hr
= DSERR_BUFFERLOST
;
1460 LeaveCriticalSection(This
->crst
);
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
;
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
;
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
);
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
;
1502 hr
= DSERR_INVALIDPARAM
;
1505 if(desc
|| rescodes
)
1507 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1511 /* No effects; we can handle that */
1516 if(!desc
|| !rescodes
)
1518 WARN("NULL desc and/or result pointer specified.\n");
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
;
1532 LeaveCriticalSection(This
->crst
);
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
;
1557 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1559 LeaveCriticalSection(This
->crst
);
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
);
1570 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
= {
1571 DS8Buffer_QueryInterface
,
1575 DS8Buffer_GetCurrentPosition
,
1576 DS8Buffer_GetFormat
,
1577 DS8Buffer_GetVolume
,
1579 DS8Buffer_GetFrequency
,
1580 DS8Buffer_GetStatus
,
1581 DS8Buffer_Initialize
,
1584 DS8Buffer_SetCurrentPosition
,
1585 DS8Buffer_SetFormat
,
1586 DS8Buffer_SetVolume
,
1588 DS8Buffer_SetFrequency
,
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
};
1604 alSource3f(source
, AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1605 -params
->vPosition
.z
);
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
);
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
);
1645 InterlockedIncrement(&This
->all_ref
);
1646 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1647 TRACE("new refcount %ld\n", ret
);
1652 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1654 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1657 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1658 TRACE("new refcount %ld\n", ret
);
1659 if(InterlockedDecrement(&This
->all_ref
) == 0)
1660 DS8Buffer_Destroy(This
);
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
);
1685 LeaveCriticalSection(This
->crst
);
1687 *pdwInsideConeAngle
= inangle
;
1688 *pdwOutsideConeAngle
= outangle
;
1692 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1694 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1697 TRACE("(%p)->(%p)\n", This
, orient
);
1700 WARN("Invalid pointer\n");
1701 return DSERR_INVALIDPARAM
;
1704 setALContext(This
->ctx
);
1705 alGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1711 orient
->z
= -dir
[2];
1715 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1717 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1720 TRACE("(%p)->(%p)\n", This
, vol
);
1723 WARN("Invalid pointer\n");
1724 return DSERR_INVALIDPARAM
;
1727 setALContext(This
->ctx
);
1728 alGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1732 *vol
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
1736 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1738 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1741 TRACE("(%p)->(%p)\n", This
, maxdist
);
1744 WARN("Invalid pointer\n");
1745 return DSERR_INVALIDPARAM
;
1748 setALContext(This
->ctx
);
1749 alGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
1757 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
1759 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1762 TRACE("(%p)->(%p)\n", This
, mindist
);
1765 WARN("Invalid pointer\n");
1766 return DSERR_INVALIDPARAM
;
1769 setALContext(This
->ctx
);
1770 alGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
1778 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
1780 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1782 TRACE("(%p)->(%p)\n", This
, mode
);
1785 WARN("Invalid pointer\n");
1786 return DSERR_INVALIDPARAM
;
1789 EnterCriticalSection(This
->crst
);
1790 *mode
= This
->ds3dmode
;
1791 LeaveCriticalSection(This
->crst
);
1796 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
1798 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1801 TRACE("(%p)->(%p)\n", This
, pos
);
1804 WARN("Invalid pointer\n");
1805 return DSERR_INVALIDPARAM
;
1808 setALContext(This
->ctx
);
1809 alGetSourcefv(This
->source
, AL_POSITION
, alpos
);
1819 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
1821 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1824 TRACE("(%p)->(%p)\n", This
, vel
);
1827 WARN("Invalid pointer\n");
1828 return DSERR_INVALIDPARAM
;
1831 setALContext(This
->ctx
);
1832 alGetSourcefv(This
->source
, AL_VELOCITY
, alvel
);
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
);
1867 LeaveCriticalSection(This
->crst
);
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;
1893 setALContext(This
->ctx
);
1894 alSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
1895 alSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
1899 LeaveCriticalSection(This
->crst
);
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
);
1921 setALContext(This
->ctx
);
1922 alSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
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
);
1950 setALContext(This
->ctx
);
1951 alSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
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
);
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
);
1979 setALContext(This
->ctx
);
1980 alSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
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
);
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
);
2008 setALContext(This
->ctx
);
2009 alSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
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;
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
;
2046 LeaveCriticalSection(This
->crst
);
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
);
2068 setALContext(This
->ctx
);
2069 alSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
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
);
2094 setALContext(This
->ctx
);
2095 alSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
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
);
2166 union BufferParamFlags dirty
= { 0 };
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;
2176 EnterCriticalSection(This
->crst
);
2177 setALContext(This
->ctx
);
2178 DS8Buffer_SetParams(This
, ds3dbuffer
, dirty
.flags
);
2181 LeaveCriticalSection(This
->crst
);
2187 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2189 DS8Buffer3D_QueryInterface
,
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
);
2224 InterlockedIncrement(&This
->all_ref
);
2225 ret
= InterlockedIncrement(&This
->not_ref
);
2226 TRACE("new refcount %ld\n", ret
);
2231 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2233 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2236 ret
= InterlockedDecrement(&This
->not_ref
);
2237 TRACE("new refcount %ld\n", ret
);
2238 if(InterlockedDecrement(&This
->all_ref
) == 0)
2239 DS8Buffer_Destroy(This
);
2244 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2246 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2247 DSBPOSITIONNOTIFY
*nots
;
2251 TRACE("(%p)->(%lu, %p))\n", iface
, count
, notifications
);
2253 EnterCriticalSection(This
->crst
);
2254 hr
= DSERR_INVALIDPARAM
;
2255 if(count
&& !notifications
)
2258 hr
= DS8Buffer_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2259 if(FAILED(hr
)) goto out
;
2261 hr
= DSERR_INVALIDCALL
;
2262 if((state
&DSBSTATUS_PLAYING
))
2267 HeapFree(GetProcessHeap(), 0, This
->notify
);
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
)
2285 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2287 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2289 HeapFree(GetProcessHeap(), 0, This
->notify
);
2290 This
->notify
= nots
;
2291 This
->nnotify
= count
;
2297 LeaveCriticalSection(This
->crst
);
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
);
2321 InterlockedIncrement(&This
->all_ref
);
2322 ret
= InterlockedIncrement(&This
->prop_ref
);
2323 TRACE("new refcount %ld\n", ret
);
2328 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2330 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2333 ret
= InterlockedDecrement(&This
->prop_ref
);
2334 TRACE("new refcount %ld\n", ret
);
2335 if(InterlockedDecrement(&This
->all_ref
) == 0)
2336 DS8Buffer_Destroy(This
);
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
,
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
);
2359 #define GET_PROP(hr, retsize, dst, dstsize, src, Type) do { \
2360 if(cbPropData >= sizeof(Type)) \
2367 *data.props = src; \
2368 *(retsize) = sizeof(Type); \
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
);
2392 case DSPROPERTY_EAXLISTENER_ROOM
:
2393 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2394 prim
->eax_prop
.lRoom
, LONG
);
2396 case DSPROPERTY_EAXLISTENER_ROOMHF
:
2397 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2398 prim
->eax_prop
.lRoomHF
, LONG
);
2401 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
2402 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2403 prim
->eax_prop
.flRoomRolloffFactor
, FLOAT
);
2406 case DSPROPERTY_EAXLISTENER_DECAYTIME
:
2407 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2408 prim
->eax_prop
.flDecayTime
, FLOAT
);
2410 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO
:
2411 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2412 prim
->eax_prop
.flDecayHFRatio
, FLOAT
);
2415 case DSPROPERTY_EAXLISTENER_REFLECTIONS
:
2416 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2417 prim
->eax_prop
.lReflections
, LONG
);
2419 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY
:
2420 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2421 prim
->eax_prop
.flReflectionsDelay
, FLOAT
);
2424 case DSPROPERTY_EAXLISTENER_REVERB
:
2425 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2426 prim
->eax_prop
.lReverb
, LONG
);
2428 case DSPROPERTY_EAXLISTENER_REVERBDELAY
:
2429 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2430 prim
->eax_prop
.flReverbDelay
, FLOAT
);
2433 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
2434 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2435 prim
->eax_prop
.dwEnvironment
, DWORD
);
2438 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
2439 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2440 prim
->eax_prop
.flEnvironmentSize
, FLOAT
);
2442 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
2443 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2444 prim
->eax_prop
.flEnvironmentDiffusion
, FLOAT
);
2447 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
2448 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2449 prim
->eax_prop
.flAirAbsorptionHF
, FLOAT
);
2452 case DSPROPERTY_EAXLISTENER_FLAGS
:
2453 GET_PROP(&hr
, pcbReturned
, pPropData
, cbPropData
,
2454 prim
->eax_prop
.dwFlags
, DWORD
);
2458 hr
= E_PROP_ID_UNSUPPORTED
;
2459 FIXME("Unhandled propid: 0x%08lx\n", dwPropID
);
2463 LeaveCriticalSection(This
->crst
);
2466 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
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
;
2501 case DSPROPERTY_EAXLISTENER_NONE
: /* not setting any property, just applying */
2505 case DSPROPERTY_EAXLISTENER_ALLPARAMETERS
:
2507 if(cbPropData
>= sizeof(EAXLISTENERPROPERTIES
))
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
,
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
);
2555 prim
->dirty
.bit
.effect
= 1;
2560 case DSPROPERTY_EAXLISTENER_ROOM
:
2561 if(cbPropData
>= sizeof(LONG
))
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
));
2573 prim
->dirty
.bit
.effect
= 1;
2577 case DSPROPERTY_EAXLISTENER_ROOMHF
:
2578 if(cbPropData
>= sizeof(LONG
))
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
));
2590 prim
->dirty
.bit
.effect
= 1;
2595 case DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR
:
2596 if(cbPropData
>= sizeof(FLOAT
))
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
);
2608 prim
->dirty
.bit
.effect
= 1;
2613 case DSPROPERTY_EAXLISTENER_DECAYTIME
:
2614 if(cbPropData
>= sizeof(FLOAT
))
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
);
2626 prim
->dirty
.bit
.effect
= 1;
2630 case DSPROPERTY_EAXLISTENER_DECAYHFRATIO
:
2631 if(cbPropData
>= sizeof(FLOAT
))
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
);
2643 prim
->dirty
.bit
.effect
= 1;
2648 case DSPROPERTY_EAXLISTENER_REFLECTIONS
:
2649 if(cbPropData
>= sizeof(LONG
))
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
));
2661 prim
->dirty
.bit
.effect
= 1;
2665 case DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY
:
2666 if(cbPropData
>= sizeof(FLOAT
))
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
);
2678 prim
->dirty
.bit
.effect
= 1;
2683 case DSPROPERTY_EAXLISTENER_REVERB
:
2684 if(cbPropData
>= sizeof(LONG
))
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
));
2696 prim
->dirty
.bit
.effect
= 1;
2700 case DSPROPERTY_EAXLISTENER_REVERBDELAY
:
2701 if(cbPropData
>= sizeof(FLOAT
))
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
);
2713 prim
->dirty
.bit
.effect
= 1;
2718 case DSPROPERTY_EAXLISTENER_ENVIRONMENT
:
2719 if(cbPropData
>= sizeof(DWORD
))
2724 } data
= { pPropData
};
2726 if(*data
.dw
<= EAX_MAX_ENVIRONMENT
)
2728 /* Get the environment index's default and pass it down to
2730 propid
= DSPROPERTY_EAXLISTENER_ALLPARAMETERS
;
2731 pPropData
= (void*)&EnvironmentDefaults
[*data
.dw
];
2732 cbPropData
= sizeof(EnvironmentDefaults
[*data
.dw
]);
2738 case DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE
:
2739 if(cbPropData
>= sizeof(FLOAT
))
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
);
2786 case DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION
:
2787 if(cbPropData
>= sizeof(FLOAT
))
2792 } data
= { pPropData
};
2794 prim
->eax_prop
.flEnvironmentDiffusion
= *data
.fl
;
2795 prim
->ExtAL
->Effectf(prim
->effect
, AL_REVERB_DIFFUSION
,
2796 prim
->eax_prop
.flEnvironmentDiffusion
);
2799 prim
->dirty
.bit
.effect
= 1;
2804 case DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
:
2805 if(cbPropData
>= sizeof(FLOAT
))
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
));
2817 prim
->dirty
.bit
.effect
= 1;
2822 case DSPROPERTY_EAXLISTENER_FLAGS
:
2823 if(cbPropData
>= sizeof(DWORD
))
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
);
2836 prim
->dirty
.bit
.effect
= 1;
2842 hr
= E_PROP_ID_UNSUPPORTED
;
2843 FIXME("Unhandled propid: 0x%08lx\n", propid
);
2847 if(hr
== DS_OK
&& immediate
)
2848 DS8Primary3D_CommitDeferredSettings(&prim
->IDirectSound3DListener_iface
);
2851 LeaveCriticalSection(prim
->crst
);
2854 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
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
);
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
;
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
;
2909 FIXME("Unhandled propid: 0x%08lx\n", dwPropID
);
2911 LeaveCriticalSection(This
->crst
);
2914 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2919 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2921 DS8BufferProp_QueryInterface
,
2922 DS8BufferProp_AddRef
,
2923 DS8BufferProp_Release
,
2926 DS8BufferProp_QuerySupport