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
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)
47 #define DS_INCOMPLETE ((HRESULT)0x08780020)
50 #ifndef WAVE_FORMAT_IEEE_FLOAT
51 #define WAVE_FORMAT_IEEE_FLOAT 3
54 /* TODO: when bufferlost is set, return from all calls except initialize with
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
)
96 list
= buf
->primary
->notifies
;
97 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
101 ERR("Buffer %p already in notification list\n", buf
);
105 if(buf
->primary
->nnotifies
== buf
->primary
->sizenotifies
)
107 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (buf
->primary
->nnotifies
+ 1) * sizeof(*list
));
110 buf
->primary
->sizenotifies
++;
112 list
[buf
->primary
->nnotifies
++] = buf
;
113 buf
->primary
->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 FIXME("Padded samples not supported (%u of %u)\n", out
->Samples
.wValidBitsPerSample
, out
->Format
.wBitsPerSample
);
211 if(out
->dwChannelMask
!= MONO
&& out
->dwChannelMask
!= STEREO
&&
212 !prim
->SupportedExt
[EXT_MCFORMATS
])
214 WARN("Multi-channel not available\n");
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
);
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";
269 WARN("Invalid float bits: %u\n", out
->Samples
.wValidBitsPerSample
);
273 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
274 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
277 else if(!IsEqualGUID(&out
->SubFormat
, &GUID_NULL
))
278 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out
->SubFormat
));
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
;
290 format
= desc
->lpwfxFormat
;
291 TRACE("Requested buffer format:\n"
292 " FormatTag = 0x%04x\n"
294 " SamplesPerSec = %lu\n"
295 " AvgBytesPerSec = %lu\n"
297 " BitsPerSample = %d\n",
298 format
->wFormatTag
, format
->nChannels
,
299 format
->nSamplesPerSec
, format
->nAvgBytesPerSec
,
300 format
->nBlockAlign
, format
->wBitsPerSample
);
302 if(format
->nBlockAlign
== 0)
304 WARN("Invalid BlockAlign specified\n");
305 return DSERR_INVALIDPARAM
;
308 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
309 * will need the EAX-RAM extension. Currently, we just tell the app it
310 * gets what it wanted. */
311 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
313 return E_OUTOFMEMORY
;
316 pBuffer
->dsbflags
= desc
->dwFlags
;
317 if((pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
)) == (DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
))
319 WARN("Hardware and software location requested\n");
322 if(!(pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCDEFER
)))
323 pBuffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
325 pBuffer
->buf_size
= desc
->dwBufferBytes
+ format
->nBlockAlign
- 1;
326 pBuffer
->buf_size
-= pBuffer
->buf_size
%format
->nBlockAlign
;
328 hr
= DSERR_BUFFERTOOSMALL
;
329 if(pBuffer
->buf_size
< DSBSIZE_MIN
)
332 hr
= DSERR_INVALIDPARAM
;
333 if(pBuffer
->buf_size
> DSBSIZE_MAX
)
336 if(!(pBuffer
->dsbflags
&DSBCAPS_STATIC
))
338 pBuffer
->segsize
= (format
->nAvgBytesPerSec
+prim
->refresh
-1) / prim
->refresh
;
339 pBuffer
->segsize
= clampI(pBuffer
->segsize
, format
->nBlockAlign
, 2048);
340 pBuffer
->segsize
+= format
->nBlockAlign
- 1;
341 pBuffer
->segsize
-= pBuffer
->segsize
%format
->nBlockAlign
;
344 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
345 fmt_str
= get_fmtstr_PCM(prim
, format
, &pBuffer
->format
);
346 else if(format
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
347 fmt_str
= get_fmtstr_FLOAT(prim
, format
, &pBuffer
->format
);
348 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
350 const WAVEFORMATEXTENSIBLE
*wfe
;
352 hr
= DSERR_CONTROLUNAVAIL
;
353 if(format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
354 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
357 wfe
= CONTAINING_RECORD(format
, const WAVEFORMATEXTENSIBLE
, Format
);
358 TRACE("Extensible values:\n"
360 " ChannelMask = 0x%lx\n"
362 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
363 debugstr_guid(&wfe
->SubFormat
));
365 fmt_str
= get_fmtstr_EXT(prim
, format
, &pBuffer
->format
);
368 ERR("Unhandled formattag 0x%04x\n", format
->wFormatTag
);
370 hr
= DSERR_INVALIDCALL
;
374 pBuffer
->buf_format
= alGetEnumValue(fmt_str
);
375 if(alGetError() != AL_NO_ERROR
|| pBuffer
->buf_format
== 0 ||
376 pBuffer
->buf_format
== -1)
378 WARN("Could not get OpenAL format from %s\n", fmt_str
);
383 pBuffer
->data
= HeapAlloc(GetProcessHeap(), 0, pBuffer
->buf_size
);
384 if(!pBuffer
->data
) goto fail
;
386 alGenBuffers(1, &pBuffer
->bid
);
393 DS8Data_Release(pBuffer
);
397 static void DS8Data_AddRef(DS8Data
*data
)
399 InterlockedIncrement(&data
->ref
);
402 /* This function is always called with the device lock held */
403 static void DS8Data_Release(DS8Data
*This
)
405 if(InterlockedDecrement(&This
->ref
)) return;
407 TRACE("Deleting %p\n", This
);
410 alDeleteBuffers(1, &This
->bid
);
413 HeapFree(GetProcessHeap(), 0, This
->data
);
414 HeapFree(GetProcessHeap(), 0, This
);
418 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*prim
, IDirectSoundBuffer
*orig
)
420 DS8Buffer
*This
= NULL
;
425 EnterCriticalSection(prim
->crst
);
426 for(i
= 0;i
< prim
->NumBufferGroups
;++i
)
428 if(prim
->BufferGroups
[i
].FreeBuffers
)
430 int idx
= CTZ64(prim
->BufferGroups
[i
].FreeBuffers
);
431 This
= prim
->BufferGroups
[i
].Buffers
+ idx
;
432 memset(This
, 0, sizeof(*This
));
433 prim
->BufferGroups
[i
].FreeBuffers
&= ~(U64(1) << idx
);
437 LeaveCriticalSection(prim
->crst
);
440 WARN("Allocating extra DS8Buffer\n");
441 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
442 if(!This
) return DSERR_OUTOFMEMORY
;
445 This
->IDirectSoundBuffer8_iface
.lpVtbl
= &DS8Buffer_Vtbl
;
446 This
->IDirectSoundBuffer_iface
.lpVtbl
= &DSBuffer_Vtbl
;
447 This
->IDirectSound3DBuffer_iface
.lpVtbl
= &DS8Buffer3d_Vtbl
;
448 This
->IDirectSoundNotify_iface
.lpVtbl
= &DS8BufferNot_Vtbl
;
449 This
->IKsPropertySet_iface
.lpVtbl
= &DS8BufferProp_Vtbl
;
451 This
->primary
= prim
;
452 This
->ctx
= prim
->ctx
;
453 This
->ExtAL
= prim
->ExtAL
;
454 This
->crst
= prim
->crst
;
455 This
->ref
= This
->all_ref
= 1;
459 DS8Buffer
*org
= impl_from_IDirectSoundBuffer(orig
);
460 hr
= DSERR_BUFFERLOST
;
463 DS8Data_AddRef(org
->buffer
);
464 This
->buffer
= org
->buffer
;
467 /* Disable until initialized.. */
468 This
->ds3dmode
= DS3DMODE_DISABLE
;
474 DS8Buffer_Destroy(This
);
478 void DS8Buffer_Destroy(DS8Buffer
*This
)
480 DS8Primary
*prim
= This
->primary
;
483 TRACE("Destroying %p\n", This
);
485 EnterCriticalSection(prim
->crst
);
486 /* Remove from list, if in list */
487 for(i
= 0;i
< prim
->nnotifies
;++i
)
489 if(This
== prim
->notifies
[i
])
491 prim
->notifies
[i
] = prim
->notifies
[--prim
->nnotifies
];
496 setALContext(This
->ctx
);
499 alSourceStop(This
->source
);
500 alSourcei(This
->source
, AL_BUFFER
, 0);
503 prim
->sources
[prim
->parent
->share
->nsources
++] = This
->source
;
506 if(This
->stream_bids
[0])
507 alDeleteBuffers(QBUFFERS
, This
->stream_bids
);
510 DS8Data_Release(This
->buffer
);
514 HeapFree(GetProcessHeap(), 0, This
->notify
);
516 for(i
= 0;i
< prim
->NumBufferGroups
;++i
)
518 DWORD_PTR idx
= This
- prim
->BufferGroups
[i
].Buffers
;
521 prim
->BufferGroups
[i
].FreeBuffers
|= U64(1) << idx
;
526 LeaveCriticalSection(prim
->crst
);
528 HeapFree(GetProcessHeap(), 0, This
);
532 static HRESULT WINAPI
DS8Buffer_QueryInterface(IDirectSoundBuffer8
*iface
, REFIID riid
, void **ppv
)
534 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
536 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
539 if(IsEqualIID(riid
, &IID_IUnknown
))
540 *ppv
= &This
->IDirectSoundBuffer8_iface
;
541 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
542 *ppv
= &This
->IDirectSoundBuffer_iface
;
543 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer8
))
545 if(This
->primary
->parent
->is_8
)
546 *ppv
= &This
->IDirectSoundBuffer8_iface
;
548 else if(IsEqualIID(riid
, &IID_IDirectSound3DBuffer
))
550 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
551 *ppv
= &This
->IDirectSound3DBuffer_iface
;
553 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
555 if((This
->buffer
->dsbflags
&DSBCAPS_CTRLPOSITIONNOTIFY
))
556 *ppv
= &This
->IDirectSoundNotify_iface
;
558 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
559 *ppv
= &This
->IKsPropertySet_iface
;
561 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
565 IUnknown_AddRef((IUnknown
*)*ppv
);
569 return E_NOINTERFACE
;
572 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
574 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
577 InterlockedIncrement(&This
->all_ref
);
578 ret
= InterlockedIncrement(&This
->ref
);
579 TRACE("new refcount %ld\n", ret
);
584 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
586 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
589 ret
= InterlockedDecrement(&This
->ref
);
590 TRACE("new refcount %ld\n", ret
);
591 if(InterlockedDecrement(&This
->all_ref
) == 0)
592 DS8Buffer_Destroy(This
);
597 static HRESULT WINAPI
DS8Buffer_GetCaps(IDirectSoundBuffer8
*iface
, DSBCAPS
*caps
)
599 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
601 TRACE("(%p)->(%p)\n", iface
, caps
);
603 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
605 WARN("Invalid DSBCAPS (%p, %lu)\n", caps
, (caps
? caps
->dwSize
: 0));
606 return DSERR_INVALIDPARAM
;
609 caps
->dwFlags
= This
->buffer
->dsbflags
;
610 caps
->dwBufferBytes
= This
->buffer
->buf_size
;
611 caps
->dwUnlockTransferRate
= 4096;
612 caps
->dwPlayCpuOverhead
= 0;
616 HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
618 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
619 ALsizei writecursor
, pos
;
622 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
625 if(!(data
->dsbflags
&DSBCAPS_STATIC
))
627 ALint queued
= QBUFFERS
;
631 EnterCriticalSection(This
->crst
);
633 setALContext(This
->ctx
);
634 alGetSourcei(This
->source
, AL_BUFFERS_QUEUED
, &queued
);
635 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
636 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
640 if(status
== AL_STOPPED
)
641 pos
= data
->segsize
*queued
+ This
->queue_base
;
643 pos
= ofs
+ This
->queue_base
;
644 if(pos
>= data
->buf_size
)
647 pos
%= data
->buf_size
;
648 else if(This
->isplaying
)
650 pos
= data
->buf_size
;
651 alSourceStop(This
->source
);
652 alSourcei(This
->source
, AL_BUFFER
, 0);
654 This
->isplaying
= FALSE
;
658 writecursor
= (data
->segsize
*QBUFFERS
+ pos
) % data
->buf_size
;
660 writecursor
= pos
% data
->buf_size
;
662 LeaveCriticalSection(This
->crst
);
666 const WAVEFORMATEX
*format
= &data
->format
.Format
;
670 setALContext(This
->ctx
);
671 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
672 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
676 pos
= (status
== AL_STOPPED
) ? data
->buf_size
: ofs
;
677 if(status
== AL_PLAYING
)
679 writecursor
= format
->nSamplesPerSec
/ This
->primary
->refresh
;
680 writecursor
*= format
->nBlockAlign
;
684 writecursor
= (writecursor
+ pos
) % data
->buf_size
;
686 TRACE("%p Play pos = %u, write pos = %u\n", This
, pos
, writecursor
);
688 if(pos
> data
->buf_size
)
690 ERR("playpos > buf_size\n");
691 pos
%= data
->buf_size
;
693 if(writecursor
>= data
->buf_size
)
695 ERR("writepos >= buf_size\n");
696 writecursor
%= data
->buf_size
;
699 if(playpos
) *playpos
= pos
;
700 if(curpos
) *curpos
= writecursor
;
705 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
707 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
711 TRACE("(%p)->(%p, %lu, %p)\n", iface
, wfx
, allocated
, written
);
715 WARN("Cannot report format or format size\n");
716 return DSERR_INVALIDPARAM
;
719 size
= sizeof(This
->buffer
->format
.Format
) + This
->buffer
->format
.Format
.cbSize
;
723 hr
= DSERR_INVALIDPARAM
;
725 memcpy(wfx
, &This
->buffer
->format
.Format
, size
);
733 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
735 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
738 TRACE("(%p)->(%p)\n", iface
, vol
);
742 WARN("Invalid pointer\n");
743 return DSERR_INVALIDPARAM
;
746 hr
= DSERR_CONTROLUNAVAIL
;
747 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
748 WARN("Volume control not set\n");
753 setALContext(This
->ctx
);
754 alGetSourcef(This
->source
, AL_GAIN
, &gain
);
758 *vol
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
765 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
767 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
770 TRACE("(%p)->(%p)\n", iface
, pan
);
774 WARN("Invalid pointer\n");
775 return DSERR_INVALIDPARAM
;
778 hr
= DSERR_CONTROLUNAVAIL
;
779 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
780 WARN("Panning control not set\n");
785 setALContext(This
->ctx
);
786 alGetSourcefv(This
->source
, AL_POSITION
, pos
);
790 *pan
= clampI((LONG
)((pos
[0]+0.5f
) * (DSBPAN_RIGHT
-DSBPAN_LEFT
)) + DSBPAN_LEFT
,
791 DSBPAN_LEFT
, DSBPAN_RIGHT
);
798 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
800 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
803 TRACE("(%p)->(%p)\n", iface
, freq
);
807 WARN("Invalid pointer\n");
808 return DSERR_INVALIDPARAM
;
811 hr
= DSERR_CONTROLUNAVAIL
;
812 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
813 WARN("Frequency control not set\n");
816 ALfloat pitch
= 1.0f
;
818 setALContext(This
->ctx
);
819 alGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
823 *freq
= (DWORD
)(This
->buffer
->format
.Format
.nSamplesPerSec
* pitch
);
830 HRESULT WINAPI
DS8Buffer_GetStatus(IDirectSoundBuffer8
*iface
, DWORD
*status
)
832 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
833 ALint state
, looping
;
835 TRACE("(%p)->(%p)\n", iface
, status
);
839 WARN("Invalid pointer\n");
840 return DSERR_INVALIDPARAM
;
844 if((This
->buffer
->dsbflags
&DSBCAPS_STATIC
))
846 setALContext(This
->ctx
);
847 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
848 alGetSourcei(This
->source
, AL_LOOPING
, &looping
);
854 EnterCriticalSection(This
->crst
);
856 setALContext(This
->ctx
);
857 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
861 if(state
!= AL_PLAYING
)
862 state
= This
->isplaying
? AL_PLAYING
: AL_PAUSED
;
863 looping
= This
->islooping
;
865 LeaveCriticalSection(This
->crst
);
868 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
870 if((This
->buffer
->dsbflags
&DSBCAPS_LOCSOFTWARE
))
871 *status
|= DSBSTATUS_LOCSOFTWARE
;
872 else if((This
->buffer
->dsbflags
&DSBCAPS_LOCHARDWARE
))
873 *status
|= DSBSTATUS_LOCHARDWARE
;
875 if(state
== AL_PLAYING
)
876 *status
|= DSBSTATUS_PLAYING
| (looping
? DSBSTATUS_LOOPING
: 0);
878 TRACE("%p status = 0x%08lx\n", This
, *status
);
882 static HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
884 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
885 DS3DBUFFER
*ds3dbuffer
;
888 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
890 EnterCriticalSection(This
->crst
);
891 setALContext(This
->ctx
);
893 hr
= DSERR_ALREADYINITIALIZED
;
899 hr
= DSERR_INVALIDPARAM
;
902 WARN("Missing DSound buffer description\n");
905 if(!desc
->lpwfxFormat
)
907 WARN("Missing buffer format (%p)\n", This
);
910 if((desc
->dwFlags
&DSBCAPS_CTRL3D
) && desc
->lpwfxFormat
->nChannels
!= 1)
912 if(This
->primary
->parent
->is_8
)
914 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
916 WARN("Can't create multi-channel 3D buffers\n");
919 ERR("Multi-channel 3D sounds are not spatialized\n");
922 hr
= DS8Data_Create(&This
->buffer
, desc
, This
->primary
);
927 DS8Data
*buf
= This
->buffer
;
929 if(buf
->format
.Format
.wBitsPerSample
== 8)
930 memset(buf
->data
, 0x80, buf
->buf_size
);
932 memset(buf
->data
, 0x00, buf
->buf_size
);
936 if(!(This
->buffer
->dsbflags
&DSBCAPS_STATIC
))
938 alGenBuffers(QBUFFERS
, This
->stream_bids
);
943 if(This
->primary
->parent
->share
->nsources
)
945 This
->source
= This
->primary
->sources
[--(This
->primary
->parent
->share
->nsources
)];
946 alSourceRewind(This
->source
);
947 alSourcef(This
->source
, AL_GAIN
, 1.0f
);
948 alSourcef(This
->source
, AL_PITCH
, 1.0f
);
954 ds3dbuffer
= &This
->params
;
955 ds3dbuffer
->dwSize
= sizeof(This
->params
);
956 ds3dbuffer
->vPosition
.x
= 0.0f
;
957 ds3dbuffer
->vPosition
.y
= 0.0f
;
958 ds3dbuffer
->vPosition
.z
= 0.0f
;
959 ds3dbuffer
->vVelocity
.x
= 0.0f
;
960 ds3dbuffer
->vVelocity
.y
= 0.0f
;
961 ds3dbuffer
->vVelocity
.z
= 0.0f
;
962 ds3dbuffer
->dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
963 ds3dbuffer
->dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
964 ds3dbuffer
->vConeOrientation
.x
= 0.0f
;
965 ds3dbuffer
->vConeOrientation
.y
= 0.0f
;
966 ds3dbuffer
->vConeOrientation
.z
= 1.0f
;
967 ds3dbuffer
->lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
968 ds3dbuffer
->flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
969 ds3dbuffer
->flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
970 ds3dbuffer
->dwMode
= DS3DMODE_NORMAL
;
972 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
974 if(This
->primary
->auxslot
!= 0)
976 alSource3i(This
->source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
980 hr
= IDirectSound3DBuffer_SetAllParameters(&This
->IDirectSound3DBuffer_iface
, ds3dbuffer
, DS3D_IMMEDIATE
);
983 ERR("SetAllParameters failed\n");
989 ALuint source
= This
->source
;
991 if(This
->primary
->auxslot
!= 0)
993 /* Simple hack to make reverb affect non-3D sounds too */
994 alSource3i(source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
995 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
998 /* Non-3D sources aren't distance attenuated */
999 This
->ds3dmode
= DS3DMODE_DISABLE
;
1000 alSource3f(source
, AL_POSITION
, 0.0f
, 0.0f
, -1.0f
);
1001 alSource3f(source
, AL_VELOCITY
, 0.0f
, 0.0f
, 0.0f
);
1002 alSource3f(source
, AL_DIRECTION
, 0.0f
, 0.0f
, 0.0f
);
1003 alSourcef(source
, AL_CONE_OUTER_GAIN
, 1.0f
);
1004 alSourcef(source
, AL_REFERENCE_DISTANCE
, 1.0f
);
1005 alSourcef(source
, AL_MAX_DISTANCE
, 1000.0f
);
1006 alSourcef(source
, AL_ROLLOFF_FACTOR
, 0.0f
);
1007 alSourcei(source
, AL_CONE_INNER_ANGLE
, 360);
1008 alSourcei(source
, AL_CONE_OUTER_ANGLE
, 360);
1009 alSourcei(source
, AL_SOURCE_RELATIVE
, AL_TRUE
);
1016 LeaveCriticalSection(This
->crst
);
1021 static HRESULT WINAPI
DS8Buffer_Lock(IDirectSoundBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1023 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1026 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1030 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1031 return DSERR_INVALIDPARAM
;
1036 if(ptr2
) *ptr2
= NULL
;
1039 if((flags
&DSBLOCK_FROMWRITECURSOR
))
1040 DS8Buffer_GetCurrentPosition(iface
, NULL
, &ofs
);
1041 else if(ofs
>= (DWORD
)This
->buffer
->buf_size
)
1043 WARN("Invalid ofs %lu\n", ofs
);
1044 return DSERR_INVALIDPARAM
;
1046 if((flags
&DSBLOCK_ENTIREBUFFER
))
1047 bytes
= This
->buffer
->buf_size
;
1048 else if(bytes
> (DWORD
)This
->buffer
->buf_size
)
1050 WARN("Invalid size %lu\n", bytes
);
1051 return DSERR_INVALIDPARAM
;
1054 if(InterlockedExchange(&This
->buffer
->locked
, TRUE
) == TRUE
)
1056 WARN("Already locked\n");
1057 return DSERR_INVALIDPARAM
;
1060 *ptr1
= This
->buffer
->data
+ ofs
;
1061 if(bytes
>= (DWORD
)This
->buffer
->buf_size
-ofs
)
1063 *len1
= This
->buffer
->buf_size
- ofs
;
1064 remain
= bytes
- *len1
;
1072 if(ptr2
&& len2
&& remain
)
1074 *ptr2
= This
->buffer
->data
;
1081 static HRESULT WINAPI
DS8Buffer_Play(IDirectSoundBuffer8
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1083 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1084 ALint state
= AL_STOPPED
;
1088 TRACE("(%p)->(%lu, %lu, %lu)\n", iface
, res1
, prio
, flags
);
1090 EnterCriticalSection(This
->crst
);
1091 setALContext(This
->ctx
);
1093 hr
= DSERR_BUFFERLOST
;
1094 if(This
->bufferlost
)
1096 WARN("Buffer %p lost\n", This
);
1100 data
= This
->buffer
;
1101 if((data
->dsbflags
&DSBCAPS_LOCDEFER
))
1103 if(!(data
->dsbflags
&(DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCSOFTWARE
)))
1105 if(flags
& DSBPLAY_LOCSOFTWARE
)
1106 data
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1108 data
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1113 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This
->buffer
, prio
);
1114 hr
= DSERR_INVALIDPARAM
;
1118 if(!(data
->dsbflags
&DSBCAPS_STATIC
))
1120 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1121 if(This
->isplaying
) state
= AL_PLAYING
;
1125 alSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1126 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1131 if(state
== AL_PLAYING
)
1134 /* alSourceQueueBuffers will implicitly set type to streaming */
1135 if((data
->dsbflags
&DSBCAPS_STATIC
))
1137 if(state
!= AL_PAUSED
)
1138 alSourcei(This
->source
, AL_BUFFER
, data
->bid
);
1139 alSourcePlay(This
->source
);
1143 alSourceRewind(This
->source
);
1144 alSourcei(This
->source
, AL_BUFFER
, 0);
1145 This
->queue_base
= This
->data_offset
% data
->buf_size
;
1148 if(alGetError() != AL_NO_ERROR
)
1150 ERR("Couldn't start source\n");
1151 alSourcei(This
->source
, AL_BUFFER
, 0);
1156 This
->isplaying
= TRUE
;
1157 This
->playflags
= flags
;
1161 DS8Buffer_addnotify(This
);
1162 DS8Primary_starttimer(This
->primary
);
1164 else if(!(data
->dsbflags
&DSBCAPS_STATIC
))
1165 DS8Primary_starttimer(This
->primary
);
1169 LeaveCriticalSection(This
->crst
);
1173 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1175 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1178 TRACE("(%p)->(%lu)\n", iface
, pos
);
1180 data
= This
->buffer
;
1181 if(pos
>= (DWORD
)data
->buf_size
)
1182 return DSERR_INVALIDPARAM
;
1184 EnterCriticalSection(This
->crst
);
1186 if(!(data
->dsbflags
&DSBCAPS_STATIC
))
1190 setALContext(This
->ctx
);
1191 /* Perform a flush, so the next timer update will restart at the
1192 * proper position */
1193 alSourceRewind(This
->source
);
1194 alSourcei(This
->source
, AL_BUFFER
, 0);
1198 This
->queue_base
= This
->data_offset
= pos
;
1203 setALContext(This
->ctx
);
1204 alSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1207 This
->lastpos
= pos
;
1209 LeaveCriticalSection(This
->crst
);
1213 static HRESULT WINAPI
DS8Buffer_SetFormat(IDirectSoundBuffer8
*iface
, const WAVEFORMATEX
*wfx
)
1215 /* This call only works on primary buffers */
1216 WARN("(%p)->(%p)\n", iface
, wfx
);
1217 return DSERR_INVALIDCALL
;
1220 static HRESULT WINAPI
DS8Buffer_SetVolume(IDirectSoundBuffer8
*iface
, LONG vol
)
1222 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1225 TRACE("(%p)->(%ld)\n", iface
, vol
);
1227 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
1229 WARN("Invalid volume (%ld)\n", vol
);
1230 return DSERR_INVALIDPARAM
;
1233 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
1234 hr
= DSERR_CONTROLUNAVAIL
;
1237 ALfloat fvol
= mB_to_gain(vol
);
1238 setALContext(This
->ctx
);
1239 alSourcef(This
->source
, AL_GAIN
, fvol
);
1246 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1248 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1251 TRACE("(%p)->(%ld)\n", iface
, pan
);
1253 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1255 WARN("invalid parameter: pan = %ld\n", pan
);
1256 return DSERR_INVALIDPARAM
;
1259 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1260 hr
= DSERR_CONTROLUNAVAIL
;
1264 pos
[0] = (ALfloat
)(pan
-DSBPAN_LEFT
)/(ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 0.5f
;
1266 /* NOTE: Strict movement along the X plane can cause the sound to jump
1267 * between left and right sharply. Using a curved path helps smooth it
1269 pos
[2] = -sqrtf(1.0f
- pos
[0]*pos
[0]);
1271 setALContext(This
->ctx
);
1272 alSourcefv(This
->source
, AL_POSITION
, pos
);
1276 if(pan
!= 0 && This
->buffer
->format
.Format
.nChannels
> 1)
1277 FIXME("Panning for multi-channel buffers is not supported\n");
1283 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1285 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1288 TRACE("(%p)->(%lu)\n", iface
, freq
);
1290 if(freq
< DSBFREQUENCY_MIN
|| freq
> DSBFREQUENCY_MAX
)
1292 WARN("invalid parameter: freq = %lu\n", freq
);
1293 return DSERR_INVALIDPARAM
;
1296 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1297 hr
= DSERR_CONTROLUNAVAIL
;
1300 ALfloat pitch
= 1.0f
;
1301 if(freq
!= DSBFREQUENCY_ORIGINAL
)
1302 pitch
= freq
/ (ALfloat
)This
->buffer
->format
.Format
.nSamplesPerSec
;
1304 setALContext(This
->ctx
);
1305 alSourcef(This
->source
, AL_PITCH
, pitch
);
1313 static HRESULT WINAPI
DS8Buffer_Stop(IDirectSoundBuffer8
*iface
)
1315 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1317 TRACE("(%p)->()\n", iface
);
1319 EnterCriticalSection(This
->crst
);
1320 setALContext(This
->ctx
);
1322 alSourcePause(This
->source
);
1325 This
->isplaying
= FALSE
;
1328 LeaveCriticalSection(This
->crst
);
1333 static HRESULT WINAPI
DS8Buffer_Unlock(IDirectSoundBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1335 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1336 DS8Data
*buf
= This
->buffer
;
1337 DWORD bufsize
= buf
->buf_size
;
1338 DWORD_PTR ofs1
, ofs2
;
1339 DWORD_PTR boundary
= (DWORD_PTR
)buf
->data
;
1342 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1344 if(InterlockedExchange(&This
->buffer
->locked
, FALSE
) == FALSE
)
1346 WARN("Not locked\n");
1347 return DSERR_INVALIDPARAM
;
1350 hr
= DSERR_INVALIDPARAM
;
1351 /* Make sure offset is between boundary and boundary + bufsize */
1352 ofs1
= (DWORD_PTR
)ptr1
;
1353 ofs2
= (DWORD_PTR
)ptr2
;
1356 if(ofs2
&& ofs2
!= boundary
)
1360 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1369 setALContext(This
->ctx
);
1370 if((buf
->dsbflags
&DSBCAPS_STATIC
))
1371 alBufferData(buf
->bid
, buf
->buf_format
, buf
->data
, buf
->buf_size
,
1372 buf
->format
.Format
.nSamplesPerSec
);
1378 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1382 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1384 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1387 TRACE("(%p)->()\n", iface
);
1389 EnterCriticalSection(This
->crst
);
1390 if(This
->primary
->parent
->prio_level
< DSSCL_WRITEPRIMARY
||
1391 iface
== This
->primary
->write_emu
)
1393 This
->bufferlost
= 0;
1397 hr
= DSERR_BUFFERLOST
;
1398 LeaveCriticalSection(This
->crst
);
1403 static HRESULT WINAPI
DS8Buffer_SetFX(IDirectSoundBuffer8
*iface
, DWORD fxcount
, DSEFFECTDESC
*desc
, DWORD
*rescodes
)
1405 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1408 TRACE("(%p)->(%lu, %p, %p)\n", This
, fxcount
, desc
, rescodes
);
1410 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFX
))
1412 WARN("FX control not set\n");
1413 return DSERR_CONTROLUNAVAIL
;
1418 if(desc
|| rescodes
)
1420 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1421 return DSERR_INVALIDPARAM
;
1424 /* No effects; we can handle that */
1428 if(!desc
|| !rescodes
)
1430 WARN("NULL desc and/or result pointer specified.\n");
1431 return DSERR_INVALIDPARAM
;
1434 /* We don't (currently) handle DSound effects */
1435 for(i
= 0;i
< fxcount
;++i
)
1437 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc
[i
].guidDSFXClass
));
1438 rescodes
[i
] = DSFXR_FAILED
;
1441 return DS_INCOMPLETE
;
1444 static HRESULT WINAPI
DS8Buffer_AcquireResources(IDirectSoundBuffer8
*iface
, DWORD flags
, DWORD fxcount
, DWORD
*rescodes
)
1446 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1448 TRACE("(%p)->(%lu, %lu, %p)\n", This
, flags
, fxcount
, rescodes
);
1450 /* effects aren't supported at the moment.. */
1451 if(fxcount
!= 0 || rescodes
)
1453 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1454 return DSERR_INVALIDPARAM
;
1457 EnterCriticalSection(This
->crst
);
1458 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1460 This
->buffer
->dsbflags
&= ~(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
);
1461 if((flags
&DSBPLAY_LOCSOFTWARE
))
1462 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1464 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1466 LeaveCriticalSection(This
->crst
);
1471 static HRESULT WINAPI
DS8Buffer_GetObjectInPath(IDirectSoundBuffer8
*iface
, REFGUID guid
, DWORD idx
, REFGUID rguidiface
, void **ppv
)
1473 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface
, debugstr_guid(guid
), idx
, debugstr_guid(rguidiface
), ppv
);
1477 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
= {
1478 DS8Buffer_QueryInterface
,
1482 DS8Buffer_GetCurrentPosition
,
1483 DS8Buffer_GetFormat
,
1484 DS8Buffer_GetVolume
,
1486 DS8Buffer_GetFrequency
,
1487 DS8Buffer_GetStatus
,
1488 DS8Buffer_Initialize
,
1491 DS8Buffer_SetCurrentPosition
,
1492 DS8Buffer_SetFormat
,
1493 DS8Buffer_SetVolume
,
1495 DS8Buffer_SetFrequency
,
1500 DS8Buffer_AcquireResources
,
1501 DS8Buffer_GetObjectInPath
1505 static HRESULT WINAPI
DSBuffer_QueryInterface(IDirectSoundBuffer
*iface
, REFIID riid
, void **ppv
)
1507 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1508 return DS8Buffer_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1511 static ULONG WINAPI
DSBuffer_AddRef(IDirectSoundBuffer
*iface
)
1513 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1514 return DS8Buffer_AddRef(&This
->IDirectSoundBuffer8_iface
);
1517 static ULONG WINAPI
DSBuffer_Release(IDirectSoundBuffer
*iface
)
1519 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1520 return DS8Buffer_Release(&This
->IDirectSoundBuffer8_iface
);
1523 static HRESULT WINAPI
DSBuffer_GetCaps(IDirectSoundBuffer
*iface
, DSBCAPS
*caps
)
1525 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1526 return DS8Buffer_GetCaps(&This
->IDirectSoundBuffer8_iface
, caps
);
1529 static HRESULT WINAPI
DSBuffer_GetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD
*playpos
, DWORD
*curpos
)
1531 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1532 return DS8Buffer_GetCurrentPosition(&This
->IDirectSoundBuffer8_iface
, playpos
, curpos
);
1535 static HRESULT WINAPI
DSBuffer_GetFormat(IDirectSoundBuffer
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
1537 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1538 return DS8Buffer_GetFormat(&This
->IDirectSoundBuffer8_iface
, wfx
, allocated
, written
);
1541 static HRESULT WINAPI
DSBuffer_GetVolume(IDirectSoundBuffer
*iface
, LONG
*vol
)
1543 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1544 return DS8Buffer_GetVolume(&This
->IDirectSoundBuffer8_iface
, vol
);
1547 static HRESULT WINAPI
DSBuffer_GetPan(IDirectSoundBuffer
*iface
, LONG
*pan
)
1549 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1550 return DS8Buffer_GetPan(&This
->IDirectSoundBuffer8_iface
, pan
);
1553 static HRESULT WINAPI
DSBuffer_GetFrequency(IDirectSoundBuffer
*iface
, DWORD
*freq
)
1555 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1556 return DS8Buffer_GetFrequency(&This
->IDirectSoundBuffer8_iface
, freq
);
1559 static HRESULT WINAPI
DSBuffer_GetStatus(IDirectSoundBuffer
*iface
, DWORD
*status
)
1561 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1562 return DS8Buffer_GetStatus(&This
->IDirectSoundBuffer8_iface
, status
);
1565 static HRESULT WINAPI
DSBuffer_Initialize(IDirectSoundBuffer
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
1567 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1568 return DS8Buffer_Initialize(&This
->IDirectSoundBuffer8_iface
, ds
, desc
);
1571 static HRESULT WINAPI
DSBuffer_Lock(IDirectSoundBuffer
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1573 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1574 return DS8Buffer_Lock(&This
->IDirectSoundBuffer8_iface
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1577 static HRESULT WINAPI
DSBuffer_Play(IDirectSoundBuffer
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1579 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1580 return DS8Buffer_Play(&This
->IDirectSoundBuffer8_iface
, res1
, prio
, flags
);
1583 static HRESULT WINAPI
DSBuffer_SetCurrentPosition(IDirectSoundBuffer
*iface
, DWORD pos
)
1585 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1586 return DS8Buffer_SetCurrentPosition(&This
->IDirectSoundBuffer8_iface
, pos
);
1589 static HRESULT WINAPI
DSBuffer_SetFormat(IDirectSoundBuffer
*iface
, const WAVEFORMATEX
*wfx
)
1591 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1592 return DS8Buffer_SetFormat(&This
->IDirectSoundBuffer8_iface
, wfx
);
1595 static HRESULT WINAPI
DSBuffer_SetVolume(IDirectSoundBuffer
*iface
, LONG vol
)
1597 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1598 return DS8Buffer_SetVolume(&This
->IDirectSoundBuffer8_iface
, vol
);
1601 static HRESULT WINAPI
DSBuffer_SetPan(IDirectSoundBuffer
*iface
, LONG pan
)
1603 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1604 return DS8Buffer_SetPan(&This
->IDirectSoundBuffer8_iface
, pan
);
1607 static HRESULT WINAPI
DSBuffer_SetFrequency(IDirectSoundBuffer
*iface
, DWORD freq
)
1609 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1610 return DS8Buffer_SetFrequency(&This
->IDirectSoundBuffer8_iface
, freq
);
1613 static HRESULT WINAPI
DSBuffer_Stop(IDirectSoundBuffer
*iface
)
1615 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1616 return DS8Buffer_Stop(&This
->IDirectSoundBuffer8_iface
);
1619 static HRESULT WINAPI
DSBuffer_Unlock(IDirectSoundBuffer
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1621 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1622 return DS8Buffer_Unlock(&This
->IDirectSoundBuffer8_iface
, ptr1
, len1
, ptr2
, len2
);
1625 static HRESULT WINAPI
DSBuffer_Restore(IDirectSoundBuffer
*iface
)
1627 DS8Buffer
*This
= impl_from_IDirectSoundBuffer(iface
);
1628 return DS8Buffer_Restore(&This
->IDirectSoundBuffer8_iface
);
1631 static const IDirectSoundBufferVtbl DSBuffer_Vtbl
= {
1632 DSBuffer_QueryInterface
,
1636 DSBuffer_GetCurrentPosition
,
1640 DSBuffer_GetFrequency
,
1642 DSBuffer_Initialize
,
1645 DSBuffer_SetCurrentPosition
,
1649 DSBuffer_SetFrequency
,
1656 void DS8Buffer_SetParams(DS8Buffer
*This
, const DS3DBUFFER
*params
, LONG flags
)
1658 const ALuint source
= This
->source
;
1659 union BufferParamFlags dirty
= { flags
};
1662 alSource3f(source
, AL_POSITION
, params
->vPosition
.x
, params
->vPosition
.y
,
1663 -params
->vPosition
.z
);
1665 alSource3f(source
, AL_VELOCITY
, params
->vVelocity
.x
, params
->vVelocity
.y
,
1666 -params
->vVelocity
.z
);
1667 if(dirty
.bit
.cone_angles
)
1669 alSourcei(source
, AL_CONE_INNER_ANGLE
, params
->dwInsideConeAngle
);
1670 alSourcei(source
, AL_CONE_OUTER_ANGLE
, params
->dwOutsideConeAngle
);
1672 if(dirty
.bit
.cone_orient
)
1673 alSource3f(source
, AL_DIRECTION
, params
->vConeOrientation
.x
,
1674 params
->vConeOrientation
.y
,
1675 -params
->vConeOrientation
.z
);
1676 if(dirty
.bit
.cone_outsidevolume
)
1677 alSourcef(source
, AL_CONE_OUTER_GAIN
, mB_to_gain(params
->lConeOutsideVolume
));
1678 if(dirty
.bit
.min_distance
)
1679 alSourcef(source
, AL_REFERENCE_DISTANCE
, params
->flMinDistance
);
1680 if(dirty
.bit
.max_distance
)
1681 alSourcef(source
, AL_MAX_DISTANCE
, params
->flMaxDistance
);
1684 This
->ds3dmode
= params
->dwMode
;
1685 alSourcei(source
, AL_SOURCE_RELATIVE
, (params
->dwMode
!=DS3DMODE_NORMAL
) ?
1686 AL_TRUE
: AL_FALSE
);
1687 alSourcef(source
, AL_ROLLOFF_FACTOR
, (params
->dwMode
==DS3DMODE_DISABLE
) ?
1688 0.0f
: This
->primary
->rollofffactor
);
1692 static HRESULT WINAPI
DS8Buffer3D_QueryInterface(IDirectSound3DBuffer
*iface
, REFIID riid
, void **ppv
)
1694 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1695 return DS8Buffer_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1698 static ULONG WINAPI
DS8Buffer3D_AddRef(IDirectSound3DBuffer
*iface
)
1700 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1703 InterlockedIncrement(&This
->all_ref
);
1704 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1705 TRACE("new refcount %ld\n", ret
);
1710 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1712 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1715 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1716 TRACE("new refcount %ld\n", ret
);
1717 if(InterlockedDecrement(&This
->all_ref
) == 0)
1718 DS8Buffer_Destroy(This
);
1723 static HRESULT WINAPI
DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer
*iface
, DWORD
*pdwInsideConeAngle
, DWORD
*pdwOutsideConeAngle
)
1725 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1726 ALint inangle
, outangle
;
1728 TRACE("(%p)->(%p, %p)\n", This
, pdwInsideConeAngle
, pdwOutsideConeAngle
);
1729 if(!pdwInsideConeAngle
|| !pdwOutsideConeAngle
)
1731 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle
, pdwOutsideConeAngle
);
1732 return DSERR_INVALIDPARAM
;
1735 EnterCriticalSection(This
->crst
);
1736 setALContext(This
->ctx
);
1738 alGetSourcei(This
->source
, AL_CONE_INNER_ANGLE
, &inangle
);
1739 alGetSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, &outangle
);
1743 LeaveCriticalSection(This
->crst
);
1745 *pdwInsideConeAngle
= inangle
;
1746 *pdwOutsideConeAngle
= outangle
;
1750 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1752 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1755 TRACE("(%p)->(%p)\n", This
, orient
);
1758 WARN("Invalid pointer\n");
1759 return DSERR_INVALIDPARAM
;
1762 setALContext(This
->ctx
);
1763 alGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1769 orient
->z
= -dir
[2];
1773 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1775 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1778 TRACE("(%p)->(%p)\n", This
, vol
);
1781 WARN("Invalid pointer\n");
1782 return DSERR_INVALIDPARAM
;
1785 setALContext(This
->ctx
);
1786 alGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1790 *vol
= clampI(gain_to_mB(gain
), DSBVOLUME_MIN
, DSBVOLUME_MAX
);
1794 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1796 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1799 TRACE("(%p)->(%p)\n", This
, maxdist
);
1802 WARN("Invalid pointer\n");
1803 return DSERR_INVALIDPARAM
;
1806 setALContext(This
->ctx
);
1807 alGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
1815 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
1817 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1820 TRACE("(%p)->(%p)\n", This
, mindist
);
1823 WARN("Invalid pointer\n");
1824 return DSERR_INVALIDPARAM
;
1827 setALContext(This
->ctx
);
1828 alGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
1836 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
1838 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1840 TRACE("(%p)->(%p)\n", This
, mode
);
1843 WARN("Invalid pointer\n");
1844 return DSERR_INVALIDPARAM
;
1847 EnterCriticalSection(This
->crst
);
1848 *mode
= This
->ds3dmode
;
1849 LeaveCriticalSection(This
->crst
);
1854 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
1856 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1859 TRACE("(%p)->(%p)\n", This
, pos
);
1862 WARN("Invalid pointer\n");
1863 return DSERR_INVALIDPARAM
;
1866 setALContext(This
->ctx
);
1867 alGetSourcefv(This
->source
, AL_POSITION
, alpos
);
1877 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
1879 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1882 TRACE("(%p)->(%p)\n", This
, vel
);
1885 WARN("Invalid pointer\n");
1886 return DSERR_INVALIDPARAM
;
1889 setALContext(This
->ctx
);
1890 alGetSourcefv(This
->source
, AL_VELOCITY
, alvel
);
1900 static HRESULT WINAPI
DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer
*iface
, DS3DBUFFER
*ds3dbuffer
)
1902 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1904 TRACE("(%p)->(%p)\n", iface
, ds3dbuffer
);
1906 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
1908 WARN("Invalid parameters %p %lu\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
1909 return DSERR_INVALIDPARAM
;
1912 EnterCriticalSection(This
->crst
);
1913 setALContext(This
->ctx
);
1915 DS8Buffer3D_GetPosition(iface
, &ds3dbuffer
->vPosition
);
1916 DS8Buffer3D_GetVelocity(iface
, &ds3dbuffer
->vVelocity
);
1917 DS8Buffer3D_GetConeAngles(iface
, &ds3dbuffer
->dwInsideConeAngle
, &ds3dbuffer
->dwOutsideConeAngle
);
1918 DS8Buffer3D_GetConeOrientation(iface
, &ds3dbuffer
->vConeOrientation
);
1919 DS8Buffer3D_GetConeOutsideVolume(iface
, &ds3dbuffer
->lConeOutsideVolume
);
1920 DS8Buffer3D_GetMinDistance(iface
, &ds3dbuffer
->flMinDistance
);
1921 DS8Buffer3D_GetMaxDistance(iface
, &ds3dbuffer
->flMaxDistance
);
1922 DS8Buffer3D_GetMode(iface
, &ds3dbuffer
->dwMode
);
1925 LeaveCriticalSection(This
->crst
);
1930 static HRESULT WINAPI
DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer
*iface
, DWORD dwInsideConeAngle
, DWORD dwOutsideConeAngle
, DWORD apply
)
1932 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1934 TRACE("(%p)->(%lu, %lu, %lu)\n", This
, dwInsideConeAngle
, dwOutsideConeAngle
, apply
);
1935 if(dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
1936 dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
1938 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle
, dwOutsideConeAngle
);
1939 return DSERR_INVALIDPARAM
;
1942 EnterCriticalSection(This
->crst
);
1943 if(apply
== DS3D_DEFERRED
)
1945 This
->params
.dwInsideConeAngle
= dwInsideConeAngle
;
1946 This
->params
.dwOutsideConeAngle
= dwOutsideConeAngle
;
1947 This
->dirty
.bit
.cone_angles
= 1;
1951 setALContext(This
->ctx
);
1952 alSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
1953 alSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
1957 LeaveCriticalSection(This
->crst
);
1962 static HRESULT WINAPI
DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
1964 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1966 TRACE("(%p)->(%f, %f, %f, %lu)\n", This
, x
, y
, z
, apply
);
1968 if(apply
== DS3D_DEFERRED
)
1970 EnterCriticalSection(This
->crst
);
1971 This
->params
.vConeOrientation
.x
= x
;
1972 This
->params
.vConeOrientation
.y
= y
;
1973 This
->params
.vConeOrientation
.z
= z
;
1974 This
->dirty
.bit
.cone_orient
= 1;
1975 LeaveCriticalSection(This
->crst
);
1979 setALContext(This
->ctx
);
1980 alSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
1988 static HRESULT WINAPI
DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG vol
, DWORD apply
)
1990 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1992 TRACE("(%p)->(%ld, %lu)\n", This
, vol
, apply
);
1993 if(vol
< DSBVOLUME_MIN
|| vol
> DSBVOLUME_MAX
)
1995 WARN("Invalid volume (%ld)\n", vol
);
1996 return DSERR_INVALIDPARAM
;
1999 if(apply
== DS3D_DEFERRED
)
2001 EnterCriticalSection(This
->crst
);
2002 This
->params
.lConeOutsideVolume
= vol
;
2003 This
->dirty
.bit
.cone_outsidevolume
= 1;
2004 LeaveCriticalSection(This
->crst
);
2008 setALContext(This
->ctx
);
2009 alSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
2017 static HRESULT WINAPI
DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE maxdist
, DWORD apply
)
2019 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2021 TRACE("(%p)->(%f, %lu)\n", This
, maxdist
, apply
);
2024 WARN("Invalid max distance (%f)\n", maxdist
);
2025 return DSERR_INVALIDPARAM
;
2028 if(apply
== DS3D_DEFERRED
)
2030 EnterCriticalSection(This
->crst
);
2031 This
->params
.flMaxDistance
= maxdist
;
2032 This
->dirty
.bit
.max_distance
= 1;
2033 LeaveCriticalSection(This
->crst
);
2037 setALContext(This
->ctx
);
2038 alSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
2046 static HRESULT WINAPI
DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE mindist
, DWORD apply
)
2048 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2050 TRACE("(%p)->(%f, %lu)\n", This
, mindist
, apply
);
2053 WARN("Invalid min distance (%f)\n", mindist
);
2054 return DSERR_INVALIDPARAM
;
2057 if(apply
== DS3D_DEFERRED
)
2059 EnterCriticalSection(This
->crst
);
2060 This
->params
.flMinDistance
= mindist
;
2061 This
->dirty
.bit
.min_distance
= 1;
2062 LeaveCriticalSection(This
->crst
);
2066 setALContext(This
->ctx
);
2067 alSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
2075 static HRESULT WINAPI
DS8Buffer3D_SetMode(IDirectSound3DBuffer
*iface
, DWORD mode
, DWORD apply
)
2077 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2079 TRACE("(%p)->(%lu, %lu)\n", This
, mode
, apply
);
2080 if(mode
!= DS3DMODE_NORMAL
&& mode
!= DS3DMODE_HEADRELATIVE
&&
2081 mode
!= DS3DMODE_DISABLE
)
2083 WARN("Invalid mode (%lu)\n", mode
);
2084 return DSERR_INVALIDPARAM
;
2087 EnterCriticalSection(This
->crst
);
2088 if(apply
== DS3D_DEFERRED
)
2090 This
->params
.dwMode
= mode
;
2091 This
->dirty
.bit
.mode
= 1;
2095 setALContext(This
->ctx
);
2096 alSourcei(This
->source
, AL_SOURCE_RELATIVE
,
2097 (mode
!= DS3DMODE_NORMAL
) ? AL_TRUE
: AL_FALSE
);
2098 alSourcef(This
->source
, AL_ROLLOFF_FACTOR
,
2099 (mode
== DS3DMODE_DISABLE
) ? 0.0f
: This
->primary
->rollofffactor
);
2100 This
->ds3dmode
= mode
;
2104 LeaveCriticalSection(This
->crst
);
2109 static HRESULT WINAPI
DS8Buffer3D_SetPosition(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2111 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2113 TRACE("(%p)->(%f, %f, %f, %lu)\n", This
, x
, y
, z
, apply
);
2115 if(apply
== DS3D_DEFERRED
)
2117 EnterCriticalSection(This
->crst
);
2118 This
->params
.vPosition
.x
= x
;
2119 This
->params
.vPosition
.y
= y
;
2120 This
->params
.vPosition
.z
= z
;
2121 This
->dirty
.bit
.pos
= 1;
2122 LeaveCriticalSection(This
->crst
);
2126 setALContext(This
->ctx
);
2127 alSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
2135 static HRESULT WINAPI
DS8Buffer3D_SetVelocity(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2137 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2139 TRACE("(%p)->(%f, %f, %f, %lu)\n", This
, x
, y
, z
, apply
);
2141 if(apply
== DS3D_DEFERRED
)
2143 EnterCriticalSection(This
->crst
);
2144 This
->params
.vVelocity
.x
= x
;
2145 This
->params
.vVelocity
.y
= y
;
2146 This
->params
.vVelocity
.z
= z
;
2147 This
->dirty
.bit
.vel
= 1;
2148 LeaveCriticalSection(This
->crst
);
2152 setALContext(This
->ctx
);
2153 alSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
2161 static HRESULT WINAPI
DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer
*iface
, const DS3DBUFFER
*ds3dbuffer
, DWORD apply
)
2163 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2164 TRACE("(%p)->(%p, %lu)\n", This
, ds3dbuffer
, apply
);
2166 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
2168 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
2169 return DSERR_INVALIDPARAM
;
2172 if(ds3dbuffer
->dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2173 ds3dbuffer
->dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2175 WARN("Invalid cone angles (%lu, %lu)\n",
2176 ds3dbuffer
->dwInsideConeAngle
, ds3dbuffer
->dwOutsideConeAngle
);
2177 return DSERR_INVALIDPARAM
;
2180 if(ds3dbuffer
->lConeOutsideVolume
> DSBVOLUME_MAX
||
2181 ds3dbuffer
->lConeOutsideVolume
< DSBVOLUME_MIN
)
2183 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer
->lConeOutsideVolume
);
2184 return DSERR_INVALIDPARAM
;
2187 if(ds3dbuffer
->flMaxDistance
< 0.0f
)
2189 WARN("Invalid max distance (%f)\n", ds3dbuffer
->flMaxDistance
);
2190 return DSERR_INVALIDPARAM
;
2193 if(ds3dbuffer
->flMinDistance
< 0.0f
)
2195 WARN("Invalid min distance (%f)\n", ds3dbuffer
->flMinDistance
);
2196 return DSERR_INVALIDPARAM
;
2199 if(ds3dbuffer
->dwMode
!= DS3DMODE_NORMAL
&&
2200 ds3dbuffer
->dwMode
!= DS3DMODE_HEADRELATIVE
&&
2201 ds3dbuffer
->dwMode
!= DS3DMODE_DISABLE
)
2203 WARN("Invalid mode (%lu)\n", ds3dbuffer
->dwMode
);
2204 return DSERR_INVALIDPARAM
;
2207 if(apply
== DS3D_DEFERRED
)
2209 EnterCriticalSection(This
->crst
);
2210 This
->params
= *ds3dbuffer
;
2211 This
->params
.dwSize
= sizeof(This
->params
);
2212 This
->dirty
.bit
.pos
= 1;
2213 This
->dirty
.bit
.vel
= 1;
2214 This
->dirty
.bit
.cone_angles
= 1;
2215 This
->dirty
.bit
.cone_orient
= 1;
2216 This
->dirty
.bit
.cone_outsidevolume
= 1;
2217 This
->dirty
.bit
.min_distance
= 1;
2218 This
->dirty
.bit
.max_distance
= 1;
2219 This
->dirty
.bit
.mode
= 1;
2220 LeaveCriticalSection(This
->crst
);
2224 union BufferParamFlags dirty
= { 0 };
2227 dirty
.bit
.cone_angles
= 1;
2228 dirty
.bit
.cone_orient
= 1;
2229 dirty
.bit
.cone_outsidevolume
= 1;
2230 dirty
.bit
.min_distance
= 1;
2231 dirty
.bit
.max_distance
= 1;
2234 EnterCriticalSection(This
->crst
);
2235 setALContext(This
->ctx
);
2236 DS8Buffer_SetParams(This
, ds3dbuffer
, dirty
.flags
);
2239 LeaveCriticalSection(This
->crst
);
2245 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2247 DS8Buffer3D_QueryInterface
,
2249 DS8Buffer3D_Release
,
2250 DS8Buffer3D_GetAllParameters
,
2251 DS8Buffer3D_GetConeAngles
,
2252 DS8Buffer3D_GetConeOrientation
,
2253 DS8Buffer3D_GetConeOutsideVolume
,
2254 DS8Buffer3D_GetMaxDistance
,
2255 DS8Buffer3D_GetMinDistance
,
2256 DS8Buffer3D_GetMode
,
2257 DS8Buffer3D_GetPosition
,
2258 DS8Buffer3D_GetVelocity
,
2259 DS8Buffer3D_SetAllParameters
,
2260 DS8Buffer3D_SetConeAngles
,
2261 DS8Buffer3D_SetConeOrientation
,
2262 DS8Buffer3D_SetConeOutsideVolume
,
2263 DS8Buffer3D_SetMaxDistance
,
2264 DS8Buffer3D_SetMinDistance
,
2265 DS8Buffer3D_SetMode
,
2266 DS8Buffer3D_SetPosition
,
2267 DS8Buffer3D_SetVelocity
2271 static HRESULT WINAPI
DS8BufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
2273 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2274 return DS8Buffer_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2277 static ULONG WINAPI
DS8BufferNot_AddRef(IDirectSoundNotify
*iface
)
2279 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2282 InterlockedIncrement(&This
->all_ref
);
2283 ret
= InterlockedIncrement(&This
->not_ref
);
2284 TRACE("new refcount %ld\n", ret
);
2289 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2291 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2294 ret
= InterlockedDecrement(&This
->not_ref
);
2295 TRACE("new refcount %ld\n", ret
);
2296 if(InterlockedDecrement(&This
->all_ref
) == 0)
2297 DS8Buffer_Destroy(This
);
2302 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2304 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2305 DSBPOSITIONNOTIFY
*nots
;
2309 TRACE("(%p)->(%lu, %p))\n", iface
, count
, notifications
);
2311 EnterCriticalSection(This
->crst
);
2312 hr
= DSERR_INVALIDPARAM
;
2313 if(count
&& !notifications
)
2316 hr
= DS8Buffer_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2317 if(FAILED(hr
)) goto out
;
2319 hr
= DSERR_INVALIDCALL
;
2320 if((state
&DSBSTATUS_PLAYING
))
2325 HeapFree(GetProcessHeap(), 0, This
->notify
);
2334 hr
= DSERR_INVALIDPARAM
;
2335 for(i
= 0;i
< count
;++i
)
2337 if(notifications
[i
].dwOffset
>= (DWORD
)This
->buffer
->buf_size
&&
2338 notifications
[i
].dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
2343 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2345 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2347 HeapFree(GetProcessHeap(), 0, This
->notify
);
2348 This
->notify
= nots
;
2349 This
->nnotify
= count
;
2355 LeaveCriticalSection(This
->crst
);
2359 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
=
2361 DS8BufferNot_QueryInterface
,
2362 DS8BufferNot_AddRef
,
2363 DS8BufferNot_Release
,
2364 DS8BufferNot_SetNotificationPositions
2368 static HRESULT WINAPI
DS8BufferProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
2370 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2371 return DS8Buffer_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2374 static ULONG WINAPI
DS8BufferProp_AddRef(IKsPropertySet
*iface
)
2376 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2379 InterlockedIncrement(&This
->all_ref
);
2380 ret
= InterlockedIncrement(&This
->prop_ref
);
2381 TRACE("new refcount %ld\n", ret
);
2386 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2388 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2391 ret
= InterlockedDecrement(&This
->prop_ref
);
2392 TRACE("new refcount %ld\n", ret
);
2393 if(InterlockedDecrement(&This
->all_ref
) == 0)
2394 DS8Buffer_Destroy(This
);
2399 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2400 handled through secondary buffers. */
2401 static HRESULT WINAPI
DS8BufferProp_Get(IKsPropertySet
*iface
,
2402 REFGUID guidPropSet
, ULONG dwPropID
,
2403 LPVOID pInstanceData
, ULONG cbInstanceData
,
2404 LPVOID pPropData
, ULONG cbPropData
,
2407 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2408 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2410 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface
, debugstr_guid(guidPropSet
),
2411 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
2418 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2424 /* Not a known buffer/source property. Pass it to the listener */
2425 hr
= IKsPropertySet_Get(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2426 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
,
2433 static HRESULT WINAPI
DS8BufferProp_Set(IKsPropertySet
*iface
,
2434 REFGUID guidPropSet
, ULONG dwPropID
,
2435 LPVOID pInstanceData
, ULONG cbInstanceData
,
2436 LPVOID pPropData
, ULONG cbPropData
)
2438 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2439 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2441 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface
, debugstr_guid(guidPropSet
),
2442 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
2445 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2451 /* Not a known buffer/source property. Pass it to the listener */
2452 hr
= IKsPropertySet_Set(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2453 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
,
2460 static HRESULT WINAPI
DS8BufferProp_QuerySupport(IKsPropertySet
*iface
,
2461 REFGUID guidPropSet
, ULONG dwPropID
,
2462 ULONG
*pTypeSupport
)
2464 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2465 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2467 TRACE("(%p)->(%s, %lu, %p)\n", iface
, debugstr_guid(guidPropSet
), dwPropID
, pTypeSupport
);
2474 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2480 /* Not a known buffer/source property. Pass it to the listener */
2481 hr
= IKsPropertySet_QuerySupport(&This
->primary
->IKsPropertySet_iface
,
2482 guidPropSet
, dwPropID
, pTypeSupport
);
2488 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2490 DS8BufferProp_QueryInterface
,
2491 DS8BufferProp_AddRef
,
2492 DS8BufferProp_Release
,
2495 DS8BufferProp_QuerySupport