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
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
39 #include "wine/debug.h"
42 #include "dsound_private.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
56 #include "dsound_private.h"
58 DEFINE_GUID(CLSID_DirectSoundPrivate
,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
60 DEFINE_GUID(DSPROPSETID_DirectSoundDevice
,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
62 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM
, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
63 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 #ifndef E_PROP_ID_UNSUPPORTED
66 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
71 #ifndef WAVE_FORMAT_IEEE_FLOAT
72 #define WAVE_FORMAT_IEEE_FLOAT 3
75 /* TODO: when bufferlost is set, return from all calls except initialize with
78 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
;
79 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
;
80 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
;
81 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
;
84 static inline DS8Buffer
*impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8
*iface
)
86 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundBuffer8_iface
);
88 /* Shares the same vtable */
89 static inline DS8Buffer
*impl_from_IDirectSoundBuffer(IDirectSoundBuffer
*iface
)
91 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundBuffer8_iface
);
94 static inline DS8Buffer
*impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer
*iface
)
96 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSound3DBuffer_iface
);
99 static inline DS8Buffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
101 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundNotify_iface
);
104 static inline DS8Buffer
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
106 return CONTAINING_RECORD(iface
, DS8Buffer
, IKsPropertySet_iface
);
110 static void CALLBACK
DS8Buffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
111 DWORD_PTR dw1
, DWORD_PTR dw2
)
117 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
120 static void DS8Buffer_starttimer(DS8Primary
*prim
)
122 DWORD triggertime
, res
= DS_TIME_RES
;
123 ALint refresh
= FAKE_REFRESH_COUNT
;
129 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
131 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
132 getALCError(prim
->parent
->device
);
134 triggertime
= 1000 / refresh
/ 2;
135 if(triggertime
< time
.wPeriodMin
)
136 triggertime
= time
.wPeriodMin
;
137 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime
, refresh
);
139 if (res
< time
.wPeriodMin
)
140 res
= time
.wPeriodMin
;
141 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
142 WARN("Could not set minimum resolution, don't expect sound\n");
144 prim
->timer_res
= res
;
145 prim
->timer_id
= timeSetEvent(triggertime
, res
, DS8Buffer_timer
, prim
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
148 /* Should be called with critsect held and context set.. */
149 static void DS8Buffer_addnotify(DS8Buffer
*buf
)
154 list
= buf
->primary
->notifies
;
155 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
159 ERR("Buffer %p already in notification list\n", buf
);
163 if(buf
->primary
->nnotifies
== buf
->primary
->sizenotifies
)
165 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (buf
->primary
->nnotifies
+ 1) * sizeof(*list
));
168 buf
->primary
->sizenotifies
++;
170 list
[buf
->primary
->nnotifies
++] = buf
;
171 buf
->primary
->notifies
= list
;
175 static const char *get_fmtstr_PCM(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
177 out
->Format
= *format
;
178 out
->Format
.cbSize
= 0;
180 if(format
->wBitsPerSample
== 8)
182 *in_type
= AL_UNSIGNED_BYTE
;
183 switch(format
->nChannels
)
185 case 1: *in_chans
= AL_MONO
;
186 return "AL_FORMAT_MONO8";
187 case 2: *in_chans
= AL_STEREO
;
188 return "AL_FORMAT_STEREO8";
189 case 4: *in_chans
= AL_QUAD
;
190 return "AL_FORMAT_QUAD8";
191 case 6: *in_chans
= AL_5POINT1
;
192 return "AL_FORMAT_51CHN8";
193 case 7: *in_chans
= AL_6POINT1
;
194 return "AL_FORMAT_61CHN8";
195 case 8: *in_chans
= AL_7POINT1
;
196 return "AL_FORMAT_71CHN8";
200 else if(format
->wBitsPerSample
== 16)
203 switch(format
->nChannels
)
205 case 1: *in_chans
= AL_MONO
;
206 return "AL_FORMAT_MONO16";
207 case 2: *in_chans
= AL_STEREO
;
208 return "AL_FORMAT_STEREO16";
209 case 4: *in_chans
= AL_QUAD
;
210 return "AL_FORMAT_QUAD16";
211 case 6: *in_chans
= AL_5POINT1
;
212 return "AL_FORMAT_51CHN16";
213 case 7: *in_chans
= AL_6POINT1
;
214 return "AL_FORMAT_61CHN16";
215 case 8: *in_chans
= AL_7POINT1
;
216 return "AL_FORMAT_71CHN16";
220 #if 0 /* Will cause incorrect byte offsets */
221 else if(format
->wBitsPerSample
== 24 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
224 switch(format
->nChannels
)
226 case 1: *in_chans
= AL_MONO
;
228 case 2: *in_chans
= AL_STEREO
;
229 return "AL_STEREO32F";
230 case 4: *in_chans
= AL_QUAD
;
232 case 6: *in_chans
= AL_5POINT1
;
233 return "AL_5POINT1_32F";
234 case 7: *in_chans
= AL_6POINT1
;
235 return "AL_6POINT1_32F";
236 case 8: *in_chans
= AL_7POINT1
;
237 return "AL_7POINT1_32F";
242 else if(format
->wBitsPerSample
== 32 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
245 switch(format
->nChannels
)
247 case 1: *in_chans
= AL_MONO
;
249 case 2: *in_chans
= AL_STEREO
;
250 return "AL_STEREO32F";
251 case 4: *in_chans
= AL_QUAD
;
253 case 6: *in_chans
= AL_5POINT1
;
254 return "AL_5POINT1_32F";
255 case 7: *in_chans
= AL_6POINT1
;
256 return "AL_6POINT1_32F";
257 case 8: *in_chans
= AL_7POINT1
;
258 return "AL_7POINT1_32F";
263 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
264 format
->wBitsPerSample
, format
->nChannels
);
268 static const char *get_fmtstr_FLOAT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
270 out
->Format
= *format
;
271 out
->Format
.cbSize
= 0;
273 if(format
->wBitsPerSample
== 32 &&
274 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
277 switch(format
->nChannels
)
279 case 1: *in_chans
= AL_MONO
;
280 return "AL_FORMAT_MONO_FLOAT32";
281 case 2: *in_chans
= AL_STEREO
;
282 return "AL_FORMAT_STEREO_FLOAT32";
283 case 4: *in_chans
= AL_QUAD
;
284 return "AL_FORMAT_QUAD32";
285 case 6: *in_chans
= AL_5POINT1
;
286 return "AL_FORMAT_51CHN32";
287 case 7: *in_chans
= AL_6POINT1
;
288 return "AL_FORMAT_61CHN32";
289 case 8: *in_chans
= AL_7POINT1
;
290 return "AL_FORMAT_71CHN32";
294 #if 0 /* Will cause incorrect byte offsets */
295 else if(format
->wBitsPerSample
== 64 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
297 *in_type
= AL_DOUBLE
;
298 switch(format
->nChannels
)
300 case 1: *in_chans
= AL_MONO
;
302 case 2: *in_chans
= AL_STEREO
;
303 return "AL_STEREO32F";
304 case 4: *in_chans
= AL_QUAD
;
306 case 6: *in_chans
= AL_5POINT1
;
307 return "AL_5POINT1_32F";
308 case 7: *in_chans
= AL_6POINT1
;
309 return "AL_6POINT1_32F";
310 case 8: *in_chans
= AL_7POINT1
;
311 return "AL_7POINT1_32F";
317 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
318 format
->wBitsPerSample
, format
->nChannels
);
322 /* Speaker configs */
323 #define MONO SPEAKER_FRONT_CENTER
324 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
325 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
326 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
327 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
328 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
329 #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)
331 static const char *get_fmtstr_EXT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
333 *out
= *(const WAVEFORMATEXTENSIBLE
*)format
;
334 out
->Format
.cbSize
= sizeof(*out
) - sizeof(out
->Format
);
336 if(!out
->Samples
.wValidBitsPerSample
)
337 out
->Samples
.wValidBitsPerSample
= out
->Format
.wBitsPerSample
;
338 else if(out
->Samples
.wValidBitsPerSample
!= out
->Format
.wBitsPerSample
)
340 FIXME("Padded samples not supported (%u of %u)\n", out
->Samples
.wValidBitsPerSample
, out
->Format
.wBitsPerSample
);
344 if(out
->dwChannelMask
!= MONO
&& out
->dwChannelMask
!= STEREO
&&
345 !prim
->SupportedExt
[EXT_MCFORMATS
] && !prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
347 WARN("Multi-channel not available\n");
351 if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
353 if(out
->Samples
.wValidBitsPerSample
== 8)
355 *in_type
= AL_UNSIGNED_BYTE
;
356 switch(out
->dwChannelMask
)
358 case MONO
: *in_chans
= AL_MONO
;
359 return "AL_FORMAT_MONO8";
360 case STEREO
: *in_chans
= AL_STEREO
;
361 return "AL_FORMAT_STEREO8";
362 case REAR
: *in_chans
= AL_REAR
;
363 return "AL_FORMAT_REAR8";
364 case QUAD
: *in_chans
= AL_QUAD
;
365 return "AL_FORMAT_QUAD8";
366 case X5DOT1
: *in_chans
= AL_5POINT1
;
367 return "AL_FORMAT_51CHN8";
368 case X6DOT1
: *in_chans
= AL_6POINT1
;
369 return "AL_FORMAT_61CHN8";
370 case X7DOT1
: *in_chans
= AL_7POINT1
;
371 return "AL_FORMAT_71CHN8";
375 else if(out
->Samples
.wValidBitsPerSample
== 16)
378 switch(out
->dwChannelMask
)
380 case MONO
: *in_chans
= AL_MONO
;
381 return "AL_FORMAT_MONO16";
382 case STEREO
: *in_chans
= AL_STEREO
;
383 return "AL_FORMAT_STEREO16";
384 case REAR
: *in_chans
= AL_REAR
;
385 return "AL_FORMAT_REAR16";
386 case QUAD
: *in_chans
= AL_QUAD
;
387 return "AL_FORMAT_QUAD16";
388 case X5DOT1
: *in_chans
= AL_5POINT1
;
389 return "AL_FORMAT_51CHN16";
390 case X6DOT1
: *in_chans
= AL_6POINT1
;
391 return "AL_FORMAT_61CHN16";
392 case X7DOT1
: *in_chans
= AL_7POINT1
;
393 return "AL_FORMAT_71CHN16";
398 else if(out
->Samples
.wValidBitsPerSample
== 24 &&
399 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
402 switch(out
->dwChannelMask
)
404 case MONO
: *in_chans
= AL_MONO
;
406 case STEREO
: *in_chans
= AL_STEREO
;
407 return "AL_STEREO32F";
408 case REAR
: *in_chans
= AL_REAR
;
410 case QUAD
: *in_chans
= AL_QUAD
;
412 case X5DOT1
: *in_chans
= AL_5POINT1
;
413 return "AL_5POINT1_32F";
414 case X6DOT1
: *in_chans
= AL_6POINT1
;
415 return "AL_6POINT1_32F";
416 case X7DOT1
: *in_chans
= AL_7POINT1
;
417 return "AL_7POINT1_32F";
422 else if(out
->Samples
.wValidBitsPerSample
== 32 &&
423 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
426 switch(out
->dwChannelMask
)
428 case MONO
: *in_chans
= AL_MONO
;
430 case STEREO
: *in_chans
= AL_STEREO
;
431 return "AL_STEREO32F";
432 case REAR
: *in_chans
= AL_REAR
;
434 case QUAD
: *in_chans
= AL_QUAD
;
436 case X5DOT1
: *in_chans
= AL_5POINT1
;
437 return "AL_5POINT1_32F";
438 case X6DOT1
: *in_chans
= AL_6POINT1
;
439 return "AL_6POINT1_32F";
440 case X7DOT1
: *in_chans
= AL_7POINT1
;
441 return "AL_7POINT1_32F";
446 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
447 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
450 else if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
451 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
453 if(out
->Samples
.wValidBitsPerSample
== 32)
456 switch(out
->dwChannelMask
)
458 case MONO
: *in_chans
= AL_MONO
;
459 return "AL_FORMAT_MONO_FLOAT32";
460 case STEREO
: *in_chans
= AL_STEREO
;
461 return "AL_FORMAT_STEREO_FLOAT32";
462 case REAR
: *in_chans
= AL_REAR
;
463 return "AL_FORMAT_REAR32";
464 case QUAD
: *in_chans
= AL_QUAD
;
465 return "AL_FORMAT_QUAD32";
466 case X5DOT1
: *in_chans
= AL_5POINT1
;
467 return "AL_FORMAT_51CHN32";
468 case X6DOT1
: *in_chans
= AL_6POINT1
;
469 return "AL_FORMAT_61CHN32";
470 case X7DOT1
: *in_chans
= AL_7POINT1
;
471 return "AL_FORMAT_71CHN32";
476 else if(out
->Samples
.wValidBitsPerSample
== 64 &&
477 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
479 *in_type
= AL_DOUBLE
;
480 switch(out
->dwChannelMask
)
482 case MONO
: *in_chans
= AL_MONO
;
484 case STEREO
: *in_chans
= AL_STEREO
;
485 return "AL_STEREO32F";
486 case REAR
: *in_chans
= AL_REAR
;
488 case QUAD
: *in_chans
= AL_QUAD
;
490 case X5DOT1
: *in_chans
= AL_5POINT1
;
491 return "AL_5POINT1_32F";
492 case X6DOT1
: *in_chans
= AL_6POINT1
;
493 return "AL_6POINT1_32F";
494 case X7DOT1
: *in_chans
= AL_7POINT1
;
495 return "AL_7POINT1_32F";
502 WARN("Invalid float bits: %u\n", out
->Samples
.wValidBitsPerSample
);
506 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
507 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
510 else if(!IsEqualGUID(&out
->SubFormat
, &GUID_NULL
))
511 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out
->SubFormat
));
515 static void DS8Data_Release(DS8Data
*This
);
516 static HRESULT
DS8Data_Create(DS8Data
**ppv
, const DSBUFFERDESC
*desc
, DS8Primary
*prim
)
518 HRESULT hr
= DSERR_INVALIDPARAM
;
519 const WAVEFORMATEX
*format
;
520 const char *fmt_str
= NULL
;
523 format
= desc
->lpwfxFormat
;
524 TRACE("Requested buffer format:\n"
525 " FormatTag = 0x%04x\n"
527 " SamplesPerSec = %u\n"
528 " AvgBytesPerSec = %u\n"
530 " BitsPerSample = %d\n",
531 format
->wFormatTag
, format
->nChannels
,
532 format
->nSamplesPerSec
, format
->nAvgBytesPerSec
,
533 format
->nBlockAlign
, format
->wBitsPerSample
);
535 if(format
->nBlockAlign
== 0)
537 WARN("Invalid BlockAlign specified\n");
538 return DSERR_INVALIDPARAM
;
541 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
542 * will need the EAX-RAM extension. Currently, we just tell the app it
543 * gets what it wanted. */
544 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
546 return E_OUTOFMEMORY
;
549 pBuffer
->dsbflags
= desc
->dwFlags
;
550 if((pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
)) == (DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
))
552 WARN("Hardware and software location requested\n");
555 if(!(pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCDEFER
)))
556 pBuffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
558 pBuffer
->buf_size
= desc
->dwBufferBytes
+ format
->nBlockAlign
- 1;
559 pBuffer
->buf_size
-= pBuffer
->buf_size
%format
->nBlockAlign
;
561 hr
= DSERR_BUFFERTOOSMALL
;
562 if(pBuffer
->buf_size
< DSBSIZE_MIN
)
565 hr
= DSERR_INVALIDPARAM
;
566 if(pBuffer
->buf_size
> DSBSIZE_MAX
)
569 pBuffer
->numsegs
= 1;
570 pBuffer
->segsize
= pBuffer
->buf_size
;
571 pBuffer
->lastsegsize
= pBuffer
->buf_size
;
573 if(!(pBuffer
->dsbflags
&DSBCAPS_STATIC
) && !prim
->ExtAL
.BufferSubData
&&
574 !prim
->ExtAL
.BufferSamplesSOFT
&& !prim
->ExtAL
.BufferDataStatic
)
576 ALCint refresh
= FAKE_REFRESH_COUNT
;
579 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
580 getALCError(prim
->parent
->device
);
582 newSize
= format
->nAvgBytesPerSec
/refresh
+ format
->nBlockAlign
- 1;
583 newSize
-= newSize
%format
->nBlockAlign
;
585 /* Make sure enough buffers are available */
586 if(newSize
> pBuffer
->buf_size
/(QBUFFERS
+2))
587 ERR("Buffer segments too large to stream (%u for %u)!\n",
588 newSize
, pBuffer
->buf_size
);
591 pBuffer
->numsegs
= pBuffer
->buf_size
/newSize
;
592 pBuffer
->segsize
= newSize
;
593 pBuffer
->lastsegsize
= pBuffer
->buf_size
- (newSize
*(pBuffer
->numsegs
-1));
594 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
595 pBuffer
->numsegs
, pBuffer
->segsize
, pBuffer
->lastsegsize
);
599 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
600 fmt_str
= get_fmtstr_PCM(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
601 else if(format
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
602 fmt_str
= get_fmtstr_FLOAT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
603 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
605 const WAVEFORMATEXTENSIBLE
*wfe
;
607 hr
= DSERR_CONTROLUNAVAIL
;
608 if(format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
609 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
612 wfe
= (const WAVEFORMATEXTENSIBLE
*)format
;
613 TRACE("Extensible values:\n"
615 " ChannelMask = %#x\n"
617 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
618 debugstr_guid(&wfe
->SubFormat
));
620 hr
= DSERR_INVALIDCALL
;
621 fmt_str
= get_fmtstr_EXT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
624 ERR("Unhandled formattag 0x%04x\n", format
->wFormatTag
);
629 pBuffer
->buf_format
= alGetEnumValue(fmt_str
);
630 if(alGetError() != AL_NO_ERROR
|| pBuffer
->buf_format
== 0 ||
631 pBuffer
->buf_format
== -1)
633 WARN("Could not get OpenAL format from %s\n", fmt_str
);
638 pBuffer
->buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
->buffers
)*pBuffer
->numsegs
);
639 pBuffer
->data
= HeapAlloc(GetProcessHeap(), 0, pBuffer
->buf_size
);
640 if(!pBuffer
->buffers
|| !pBuffer
->data
)
643 alGenBuffers(pBuffer
->numsegs
, pBuffer
->buffers
);
650 DS8Data_Release(pBuffer
);
654 static void DS8Data_AddRef(DS8Data
*data
)
656 InterlockedIncrement(&data
->ref
);
659 /* This function is always called with the device lock held */
660 static void DS8Data_Release(DS8Data
*This
)
662 if(InterlockedDecrement(&This
->ref
)) return;
664 TRACE("Deleting %p\n", This
);
665 if (This
->buffers
&& This
->buffers
[0])
667 alDeleteBuffers(This
->numsegs
, This
->buffers
);
670 HeapFree(GetProcessHeap(), 0, This
->buffers
);
671 HeapFree(GetProcessHeap(), 0, This
->data
);
672 HeapFree(GetProcessHeap(), 0, This
);
675 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*parent
, IDirectSoundBuffer
*orig
)
677 HRESULT hr
= DSERR_OUTOFMEMORY
;
682 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
685 This
->IDirectSoundBuffer8_iface
.lpVtbl
= (IDirectSoundBuffer8Vtbl
*)&DS8Buffer_Vtbl
;
686 This
->IDirectSound3DBuffer_iface
.lpVtbl
= (IDirectSound3DBufferVtbl
*)&DS8Buffer3d_Vtbl
;
687 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DS8BufferNot_Vtbl
;
688 This
->IKsPropertySet_iface
.lpVtbl
= (IKsPropertySetVtbl
*)&DS8BufferProp_Vtbl
;
690 This
->primary
= parent
;
691 This
->ctx
= parent
->ctx
;
692 This
->ExtAL
= &parent
->ExtAL
;
693 This
->crst
= &parent
->crst
;
694 This
->ref
= This
->all_ref
= 1;
698 DS8Buffer
*org
= impl_from_IDirectSoundBuffer(orig
);
699 hr
= DSERR_BUFFERLOST
;
702 DS8Data_AddRef(org
->buffer
);
703 This
->buffer
= org
->buffer
;
706 /* Append to buffer list */
707 bufs
= parent
->buffers
;
708 if(parent
->nbuffers
== parent
->sizebuffers
)
710 bufs
= HeapReAlloc(GetProcessHeap(), 0, bufs
, sizeof(*bufs
)*(1+parent
->nbuffers
));
711 hr
= DSERR_OUTOFMEMORY
;
713 parent
->sizebuffers
++;
715 parent
->buffers
= bufs
;
716 bufs
[parent
->nbuffers
++] = This
;
718 /* Disable until initialized.. */
719 This
->ds3dmode
= DS3DMODE_DISABLE
;
725 DS8Buffer_Destroy(This
);
729 void DS8Buffer_Destroy(DS8Buffer
*This
)
731 DS8Primary
*prim
= This
->primary
;
734 TRACE("Destroying %p\n", This
);
736 EnterCriticalSection(&prim
->crst
);
737 /* Remove from list, if in list */
738 for(idx
= 0;idx
< prim
->nnotifies
;++idx
)
740 if(This
== prim
->notifies
[idx
])
742 prim
->notifies
[idx
] = prim
->notifies
[--prim
->nnotifies
];
746 for(idx
= 0;idx
< prim
->nbuffers
;++idx
)
748 if(prim
->buffers
[idx
] == This
)
750 prim
->buffers
[idx
] = prim
->buffers
[--prim
->nbuffers
];
755 setALContext(This
->ctx
);
760 alSourceStop(This
->source
);
761 alSourcei(This
->source
, AL_BUFFER
, 0);
764 sources
= prim
->sources
;
765 if(prim
->nsources
== prim
->sizesources
)
767 sources
= HeapReAlloc(GetProcessHeap(), 0, sources
, sizeof(*sources
)*(prim
->nsources
+1));
769 alDeleteSources(1, &This
->source
);
775 sources
[prim
->nsources
++] = This
->source
;
776 prim
->sources
= sources
;
780 LeaveCriticalSection(&prim
->crst
);
783 DS8Data_Release(This
->buffer
);
787 HeapFree(GetProcessHeap(), 0, This
->notify
);
788 HeapFree(GetProcessHeap(), 0, This
);
792 static HRESULT WINAPI
DS8Buffer_QueryInterface(IDirectSoundBuffer8
*iface
, REFIID riid
, void **ppv
)
794 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
796 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
799 if(IsEqualIID(riid
, &IID_IUnknown
) ||
800 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
801 *ppv
= &This
->IDirectSoundBuffer8_iface
;
802 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer8
))
804 if(This
->primary
->parent
->is_8
)
805 *ppv
= &This
->IDirectSoundBuffer8_iface
;
807 else if(IsEqualIID(riid
, &IID_IDirectSound3DBuffer
))
809 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
810 *ppv
= &This
->IDirectSound3DBuffer_iface
;
812 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
814 if((This
->buffer
->dsbflags
&DSBCAPS_CTRLPOSITIONNOTIFY
))
815 *ppv
= &This
->IDirectSoundNotify_iface
;
817 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
818 *ppv
= &This
->IKsPropertySet_iface
;
820 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
824 IUnknown_AddRef((IUnknown
*)*ppv
);
828 return E_NOINTERFACE
;
831 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
833 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
836 InterlockedIncrement(&This
->all_ref
);
837 ret
= InterlockedIncrement(&This
->ref
);
838 TRACE("new refcount %d\n", ret
);
843 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
845 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
848 ret
= InterlockedDecrement(&This
->ref
);
849 TRACE("new refcount %d\n", ret
);
850 if(InterlockedDecrement(&This
->all_ref
) == 0)
851 DS8Buffer_Destroy(This
);
856 static HRESULT WINAPI
DS8Buffer_GetCaps(IDirectSoundBuffer8
*iface
, DSBCAPS
*caps
)
858 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
860 TRACE("(%p)->(%p)\n", iface
, caps
);
862 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
864 WARN("Invalid DSBCAPS (%p, %u)\n", caps
, (caps
? caps
->dwSize
: 0));
865 return DSERR_INVALIDPARAM
;
868 caps
->dwFlags
= This
->buffer
->dsbflags
;
869 caps
->dwBufferBytes
= This
->buffer
->buf_size
;
870 caps
->dwUnlockTransferRate
= 4096;
871 caps
->dwPlayCpuOverhead
= 0;
875 static HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
877 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
878 WAVEFORMATEX
*format
= &This
->buffer
->format
.Format
;
879 UINT writecursor
, pos
;
881 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
883 EnterCriticalSection(This
->crst
);
884 setALContext(This
->ctx
);
886 if(This
->buffer
->numsegs
> 1)
888 ALint queued
= QBUFFERS
;
889 alGetSourcei(This
->source
, AL_BUFFERS_QUEUED
, &queued
);
892 pos
= (This
->curidx
+This
->buffer
->numsegs
-queued
)%This
->buffer
->numsegs
;
893 pos
*= This
->buffer
->segsize
;
894 writecursor
= This
->curidx
* This
->buffer
->segsize
;
896 else if(This
->ExtAL
->BufferSubData
|| This
->ExtAL
->BufferSamplesSOFT
)
898 ALint rwpos
[2] = { 0, 0 };
900 alGetSourceiv(This
->source
, AL_BYTE_RW_OFFSETS_SOFT
, rwpos
);
904 writecursor
= rwpos
[1];
911 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
912 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
916 if(status
== AL_PLAYING
)
918 writecursor
= format
->nSamplesPerSec
/ 100;
919 writecursor
*= format
->nBlockAlign
;
923 writecursor
= (writecursor
+ pos
) % This
->buffer
->buf_size
;
925 TRACE("%p Play pos = %u, write pos = %u\n", This
, pos
, writecursor
);
926 if(pos
>= This
->buffer
->buf_size
)
928 ERR("playpos >= buf_size\n");
929 pos
%= This
->buffer
->buf_size
;
931 if(writecursor
>= This
->buffer
->buf_size
)
933 ERR("writepos >= buf_size\n");
934 writecursor
%= This
->buffer
->buf_size
;
937 if(playpos
) *playpos
= pos
;
938 if(curpos
) *curpos
= writecursor
;
941 LeaveCriticalSection(This
->crst
);
946 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
948 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
952 TRACE("(%p)->(%p, %u, %p)\n", iface
, wfx
, allocated
, written
);
956 WARN("Cannot report format or format size\n");
957 return DSERR_INVALIDPARAM
;
960 EnterCriticalSection(This
->crst
);
961 size
= sizeof(This
->buffer
->format
.Format
) + This
->buffer
->format
.Format
.cbSize
;
965 hr
= DSERR_INVALIDPARAM
;
967 memcpy(wfx
, &This
->buffer
->format
.Format
, size
);
971 LeaveCriticalSection(This
->crst
);
976 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
978 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
981 TRACE("(%p)->(%p)\n", iface
, vol
);
985 WARN("Invalid pointer\n");
986 return DSERR_INVALIDPARAM
;
989 EnterCriticalSection(This
->crst
);
991 hr
= DSERR_CONTROLUNAVAIL
;
992 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
993 WARN("Volume control not set\n");
998 setALContext(This
->ctx
);
999 alGetSourcef(This
->source
, AL_GAIN
, &gain
);
1003 *vol
= gain_to_mB(gain
);
1004 *vol
= min(*vol
, DSBVOLUME_MAX
);
1005 *vol
= max(*vol
, DSBVOLUME_MIN
);
1010 LeaveCriticalSection(This
->crst
);
1014 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
1016 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1019 TRACE("(%p)->(%p)\n", iface
, pan
);
1023 WARN("Invalid pointer\n");
1024 return DSERR_INVALIDPARAM
;
1027 EnterCriticalSection(This
->crst
);
1029 hr
= DSERR_CONTROLUNAVAIL
;
1030 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1031 WARN("Panning control not set\n");
1036 setALContext(This
->ctx
);
1037 alGetSourcefv(This
->source
, AL_POSITION
, pos
);
1041 *pan
= (LONG
)((pos
[0]+1.0) * (DSBPAN_RIGHT
-DSBPAN_LEFT
) / 2.0 + 0.5) + DSBPAN_LEFT
;
1042 *pan
= min(*pan
, DSBPAN_RIGHT
);
1043 *pan
= max(*pan
, DSBPAN_LEFT
);
1048 LeaveCriticalSection(This
->crst
);
1052 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
1054 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1057 TRACE("(%p)->(%p)\n", iface
, freq
);
1061 WARN("Invalid pointer\n");
1062 return DSERR_INVALIDPARAM
;
1065 EnterCriticalSection(This
->crst
);
1067 hr
= DSERR_CONTROLUNAVAIL
;
1068 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1069 WARN("Frequency control not set\n");
1072 ALfloat pitch
= 1.0f
;
1074 setALContext(This
->ctx
);
1075 alGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
1079 *freq
= (DWORD
)(This
->buffer
->format
.Format
.nSamplesPerSec
* pitch
);
1084 LeaveCriticalSection(This
->crst
);
1088 static HRESULT WINAPI
DS8Buffer_GetStatus(IDirectSoundBuffer8
*iface
, DWORD
*status
)
1090 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1091 ALint state
, looping
;
1093 TRACE("(%p)->(%p)\n", iface
, status
);
1097 WARN("Invalid pointer\n");
1098 return DSERR_INVALIDPARAM
;
1101 EnterCriticalSection(This
->crst
);
1103 setALContext(This
->ctx
);
1104 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1105 looping
= This
->islooping
;
1106 if(This
->buffer
->numsegs
== 1)
1107 alGetSourcei(This
->source
, AL_LOOPING
, &looping
);
1108 else if(state
!= AL_PLAYING
)
1109 state
= This
->isplaying
? AL_PLAYING
: AL_PAUSED
;
1114 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1116 if((This
->buffer
->dsbflags
&DSBCAPS_LOCSOFTWARE
))
1117 *status
|= DSBSTATUS_LOCSOFTWARE
;
1118 else if((This
->buffer
->dsbflags
&DSBCAPS_LOCHARDWARE
))
1119 *status
|= DSBSTATUS_LOCHARDWARE
;
1121 if(state
== AL_PLAYING
)
1122 *status
|= DSBSTATUS_PLAYING
| (looping
? DSBSTATUS_LOOPING
: 0);
1124 LeaveCriticalSection(This
->crst
);
1129 static HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
1131 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1132 DS3DBUFFER
*ds3dbuffer
;
1135 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
1137 EnterCriticalSection(This
->crst
);
1138 setALContext(This
->ctx
);
1140 hr
= DSERR_ALREADYINITIALIZED
;
1146 hr
= DSERR_INVALIDPARAM
;
1149 WARN("Missing DSound buffer description\n");
1152 if(!desc
->lpwfxFormat
)
1154 WARN("Missing buffer format (%p)\n", This
);
1157 if((desc
->dwFlags
&DSBCAPS_CTRL3D
) && desc
->lpwfxFormat
->nChannels
!= 1)
1159 if(This
->primary
->parent
->is_8
)
1161 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1163 WARN("Can't create multi-channel 3D buffers\n");
1166 ERR("Multi-channel 3D sounds are not spatialized\n");
1169 hr
= DS8Data_Create(&This
->buffer
, desc
, This
->primary
);
1174 DS8Data
*buf
= This
->buffer
;
1176 if(buf
->in_type
== AL_UNSIGNED_BYTE
)
1177 memset(buf
->data
, 0x80, buf
->buf_size
);
1179 memset(buf
->data
, 0x00, buf
->buf_size
);
1181 if(This
->ExtAL
->BufferDataStatic
)
1182 This
->ExtAL
->BufferDataStatic(buf
->buffers
[0], buf
->buf_format
,
1183 buf
->data
, buf
->buf_size
,
1184 buf
->format
.Format
.nSamplesPerSec
);
1185 else if(This
->ExtAL
->BufferSamplesSOFT
)
1186 This
->ExtAL
->BufferSamplesSOFT(buf
->buffers
[0],
1187 buf
->format
.Format
.nSamplesPerSec
, buf
->buf_format
,
1188 buf
->buf_size
/buf
->format
.Format
.nBlockAlign
,
1189 buf
->in_chans
, buf
->in_type
, buf
->data
);
1190 else if(This
->ExtAL
->BufferSubData
)
1191 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1192 buf
->data
, buf
->buf_size
,
1193 buf
->format
.Format
.nSamplesPerSec
);
1199 if(This
->primary
->nsources
)
1201 This
->source
= This
->primary
->sources
[--This
->primary
->nsources
];
1202 alSourcef(This
->source
, AL_GAIN
, 1.0f
);
1203 alSourcef(This
->source
, AL_PITCH
, 1.0f
);
1208 alGenSources(1, &This
->source
);
1209 if(alGetError() != AL_NO_ERROR
)
1213 ds3dbuffer
= &This
->ds3dbuffer
;
1214 ds3dbuffer
->dwSize
= sizeof(*ds3dbuffer
);
1215 ds3dbuffer
->vPosition
.x
= 0.0;
1216 ds3dbuffer
->vPosition
.y
= 0.0;
1217 ds3dbuffer
->vPosition
.z
= 0.0;
1218 ds3dbuffer
->vVelocity
.x
= 0.0;
1219 ds3dbuffer
->vVelocity
.y
= 0.0;
1220 ds3dbuffer
->vVelocity
.z
= 0.0;
1221 ds3dbuffer
->dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1222 ds3dbuffer
->dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1223 ds3dbuffer
->vConeOrientation
.x
= 0.0;
1224 ds3dbuffer
->vConeOrientation
.y
= 0.0;
1225 ds3dbuffer
->vConeOrientation
.z
= 1.0;
1226 ds3dbuffer
->lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1227 ds3dbuffer
->flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1228 ds3dbuffer
->flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1229 ds3dbuffer
->dwMode
= DS3DMODE_NORMAL
;
1231 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
1233 if(This
->primary
->auxslot
!= 0)
1235 alSource3i(This
->source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1239 hr
= IDirectSound3DBuffer_SetAllParameters(&This
->IDirectSound3DBuffer_iface
, ds3dbuffer
, DS3D_IMMEDIATE
);
1242 ERR("SetAllParameters failed\n");
1248 ALuint source
= This
->source
;
1250 if(This
->primary
->auxslot
!= 0)
1252 /* Simple hack to make reverb affect non-3D sounds too */
1253 alSource3i(source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1254 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1257 /* Non-3D sources aren't distance attenuated */
1258 This
->ds3dmode
= DS3DMODE_DISABLE
;
1259 alSource3f(source
, AL_POSITION
, 0.0f
, 1.0f
, 0.0f
);
1260 alSource3f(source
, AL_VELOCITY
, 0.0f
, 0.0f
, 0.0f
);
1261 alSource3f(source
, AL_DIRECTION
, 0.0f
, 0.0f
, 0.0f
);
1262 alSourcef(source
, AL_CONE_OUTER_GAIN
, 1.0f
);
1263 alSourcef(source
, AL_REFERENCE_DISTANCE
, 1.0f
);
1264 alSourcef(source
, AL_MAX_DISTANCE
, 1000.0f
);
1265 alSourcef(source
, AL_ROLLOFF_FACTOR
, 0.0f
);
1266 alSourcei(source
, AL_CONE_INNER_ANGLE
, 360);
1267 alSourcei(source
, AL_CONE_OUTER_ANGLE
, 360);
1268 alSourcei(source
, AL_SOURCE_RELATIVE
, AL_TRUE
);
1275 LeaveCriticalSection(This
->crst
);
1280 static HRESULT WINAPI
DS8Buffer_Lock(IDirectSoundBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1282 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1286 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1290 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1291 return DSERR_INVALIDPARAM
;
1294 EnterCriticalSection(This
->crst
);
1295 setALContext(This
->ctx
);
1299 if(ptr2
) *ptr2
= NULL
;
1302 hr
= DSERR_INVALIDPARAM
;
1303 if((flags
&DSBLOCK_FROMWRITECURSOR
))
1304 DS8Buffer_GetCurrentPosition(iface
, NULL
, &ofs
);
1305 else if(ofs
>= This
->buffer
->buf_size
)
1307 WARN("Invalid ofs %u\n", ofs
);
1310 if((flags
&DSBLOCK_ENTIREBUFFER
))
1311 bytes
= This
->buffer
->buf_size
;
1312 else if(bytes
> This
->buffer
->buf_size
)
1314 WARN("Invalid size %u\n", bytes
);
1318 *ptr1
= This
->buffer
->data
+ ofs
;
1319 if(ofs
+bytes
>= This
->buffer
->buf_size
)
1321 *len1
= This
->buffer
->buf_size
- ofs
;
1322 remain
= bytes
- *len1
;
1330 This
->buffer
->locked
= TRUE
;
1332 if(ptr2
&& len2
&& remain
)
1334 *ptr2
= This
->buffer
->data
;
1341 LeaveCriticalSection(This
->crst
);
1345 static HRESULT WINAPI
DS8Buffer_Play(IDirectSoundBuffer8
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1347 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1348 ALint type
, state
= AL_STOPPED
;
1352 TRACE("%p\n", This
);
1354 EnterCriticalSection(This
->crst
);
1355 setALContext(This
->ctx
);
1357 hr
= DSERR_BUFFERLOST
;
1358 if(This
->bufferlost
)
1360 WARN("Buffer %p lost\n", This
);
1364 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1366 if(!(This
->buffer
->dsbflags
&(DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCSOFTWARE
)))
1368 if(flags
& DSBPLAY_LOCSOFTWARE
)
1369 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1371 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1376 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This
->buffer
, prio
);
1377 hr
= DSERR_INVALIDPARAM
;
1381 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1382 if(This
->buffer
->numsegs
> 1)
1384 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1385 if(state
!= AL_PLAYING
&& This
->isplaying
)
1390 alGetSourcei(This
->source
, AL_SOURCE_TYPE
, &type
);
1391 alSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1396 if(state
== AL_PLAYING
)
1399 /* alSourceQueueBuffers will implicitly set type to streaming */
1400 if(This
->buffer
->numsegs
== 1)
1402 if(type
!= AL_STATIC
)
1403 alSourcei(This
->source
, AL_BUFFER
, This
->buffer
->buffers
[0]);
1404 alSourcePlay(This
->source
);
1406 if(alGetError() != AL_NO_ERROR
)
1408 ERR("Couldn't start source\n");
1409 This
->curidx
= (This
->buffer
->numsegs
-1+This
->curidx
)%This
->buffer
->numsegs
;
1410 alSourcei(This
->source
, AL_BUFFER
, 0);
1415 This
->isplaying
= TRUE
;
1419 DS8Buffer_addnotify(This
);
1420 DS8Buffer_starttimer(This
->primary
);
1422 else if(This
->buffer
->numsegs
> 1)
1423 DS8Buffer_starttimer(This
->primary
);
1427 LeaveCriticalSection(This
->crst
);
1431 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1433 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1435 TRACE("%p\n", This
);
1437 EnterCriticalSection(This
->crst
);
1438 setALContext(This
->ctx
);
1440 hr
= DSERR_INVALIDPARAM
;
1441 if(pos
>= This
->buffer
->buf_size
)
1444 if(This
->buffer
->numsegs
> 1)
1446 DS8Data
*buf
= This
->buffer
;
1447 This
->curidx
= pos
/buf
->segsize
;
1448 if(This
->curidx
>= buf
->numsegs
)
1449 This
->curidx
= buf
->numsegs
- 1;
1452 alSourceStop(This
->source
);
1453 alSourcei(This
->source
, AL_BUFFER
, 0);
1458 alSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1459 This
->lastpos
= pos
;
1464 LeaveCriticalSection(This
->crst
);
1468 static HRESULT WINAPI
DS8Buffer_SetFormat(IDirectSoundBuffer8
*iface
, const WAVEFORMATEX
*wfx
)
1470 /* This call only works on primary buffers */
1471 WARN("(%p)->(%p)\n", iface
, wfx
);
1472 return DSERR_INVALIDCALL
;
1475 static HRESULT WINAPI
DS8Buffer_SetVolume(IDirectSoundBuffer8
*iface
, LONG vol
)
1477 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1480 TRACE("(%p)->(%d)\n", iface
, vol
);
1482 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
1484 WARN("Invalid volume (%d)\n", vol
);
1485 return DSERR_INVALIDPARAM
;
1488 EnterCriticalSection(This
->crst
);
1489 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
1490 hr
= DSERR_CONTROLUNAVAIL
;
1493 ALfloat fvol
= mB_to_gain(vol
);
1494 setALContext(This
->ctx
);
1495 alSourcef(This
->source
, AL_GAIN
, fvol
);
1498 LeaveCriticalSection(This
->crst
);
1503 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1505 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1508 TRACE("(%p)->(%d)\n", iface
, pan
);
1510 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1512 WARN("invalid parameter: pan = %d\n", pan
);
1513 return DSERR_INVALIDPARAM
;
1516 EnterCriticalSection(This
->crst
);
1517 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1518 hr
= DSERR_CONTROLUNAVAIL
;
1522 pos
[0] = (pan
-DSBPAN_LEFT
) * 2.0 / (ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 1.0;
1523 /* NOTE: Strict movement along the X plane can cause the sound to jump
1524 * between left and right sharply. Using a curved path helps smooth it
1526 pos
[1] = sqrt(1.0 - pos
[0]*pos
[0]);
1529 setALContext(This
->ctx
);
1530 alSourcefv(This
->source
, AL_POSITION
, pos
);
1534 if(pan
!= 0 && This
->buffer
->format
.Format
.nChannels
> 1)
1535 FIXME("Panning for multi-channel buffers is not supported\n");
1537 LeaveCriticalSection(This
->crst
);
1542 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1544 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1547 TRACE("(%p)->(%u)\n", iface
, freq
);
1549 if(freq
< DSBFREQUENCY_MIN
|| freq
> DSBFREQUENCY_MAX
)
1551 WARN("invalid parameter: freq = %d\n", freq
);
1552 return DSERR_INVALIDPARAM
;
1555 EnterCriticalSection(This
->crst
);
1556 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1557 hr
= DSERR_CONTROLUNAVAIL
;
1560 ALfloat pitch
= 1.0f
;
1561 if(freq
!= DSBFREQUENCY_ORIGINAL
)
1562 pitch
= freq
/ (ALfloat
)This
->buffer
->format
.Format
.nSamplesPerSec
;
1564 setALContext(This
->ctx
);
1565 alSourcef(This
->source
, AL_PITCH
, pitch
);
1569 LeaveCriticalSection(This
->crst
);
1573 static HRESULT WINAPI
DS8Buffer_Stop(IDirectSoundBuffer8
*iface
)
1575 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1578 TRACE("(%p)->()\n", iface
);
1580 EnterCriticalSection(This
->crst
);
1581 setALContext(This
->ctx
);
1583 alSourcePause(This
->source
);
1585 /* Mac OS X doesn't immediately report state change
1586 * if Play() is immediately called after Stop, this can be fatal,
1587 * the buffer would never be restarted
1591 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1592 if(state
!= AL_PLAYING
)
1597 This
->isplaying
= FALSE
;
1600 LeaveCriticalSection(This
->crst
);
1605 static HRESULT WINAPI
DS8Buffer_Unlock(IDirectSoundBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1607 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1608 DS8Data
*buf
= This
->buffer
;
1609 DWORD bufsize
= buf
->buf_size
;
1610 DWORD_PTR ofs1
, ofs2
;
1611 DWORD_PTR boundary
= (DWORD_PTR
)buf
->data
;
1614 TRACE("(%p)->(%p, %u, %p, %u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1616 EnterCriticalSection(This
->crst
);
1617 setALContext(This
->ctx
);
1619 This
->buffer
->locked
= 0;
1620 hr
= DSERR_INVALIDPARAM
;
1622 /* Make sure offset is between boundary and boundary + bufsize */
1623 ofs1
= (DWORD_PTR
)ptr1
;
1624 ofs2
= (DWORD_PTR
)ptr2
;
1627 if(ofs2
&& ofs2
!= boundary
)
1631 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1640 if(This
->ExtAL
->BufferDataStatic
)
1643 if(This
->ExtAL
->BufferSubSamplesSOFT
)
1645 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1647 ptr1
= (BYTE
*)ptr1
- (ofs1
%format
->nBlockAlign
);
1648 ofs1
/= format
->nBlockAlign
;
1649 len1
/= format
->nBlockAlign
;
1651 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs1
, len1
,
1652 buf
->in_chans
, buf
->in_type
, ptr1
);
1653 ptr2
= (BYTE
*)ptr2
- (ofs2
%format
->nBlockAlign
);
1654 ofs2
/= format
->nBlockAlign
;
1655 len2
/= format
->nBlockAlign
;
1657 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs2
, len2
,
1658 buf
->in_chans
, buf
->in_type
, ptr2
);
1661 else if(This
->ExtAL
->BufferSubData
)
1663 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1665 len1
-= len1
%format
->nBlockAlign
;
1667 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr1
,
1669 len2
-= len2
%format
->nBlockAlign
;
1671 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr2
,
1677 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1678 buf
->data
, buf
->buf_size
,
1679 buf
->format
.Format
.nSamplesPerSec
);
1685 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1687 LeaveCriticalSection(This
->crst
);
1691 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1693 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1696 TRACE("(%p)->()\n", iface
);
1698 EnterCriticalSection(This
->crst
);
1699 if(This
->primary
->parent
->prio_level
< DSSCL_WRITEPRIMARY
||
1700 iface
== This
->primary
->write_emu
)
1702 This
->bufferlost
= 0;
1706 hr
= DSERR_BUFFERLOST
;
1707 LeaveCriticalSection(This
->crst
);
1712 static HRESULT WINAPI
DS8Buffer_SetFX(IDirectSoundBuffer8
*iface
, DWORD fxcount
, DSEFFECTDESC
*desc
, DWORD
*rescodes
)
1714 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1717 TRACE("(%p)->(%u, %p, %p)\n", This
, fxcount
, desc
, rescodes
);
1719 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFX
))
1721 WARN("FX control not set\n");
1722 return DSERR_CONTROLUNAVAIL
;
1727 if(desc
|| rescodes
)
1729 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1730 return DSERR_INVALIDPARAM
;
1733 /* No effects; we can handle that */
1737 if(!desc
|| !rescodes
)
1739 WARN("NULL desc and/or result pointer specified.\n");
1740 return DSERR_INVALIDPARAM
;
1743 /* We don't (currently) handle DSound effects */
1744 for(i
= 0;i
< fxcount
;++i
)
1746 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc
[i
].guidDSFXClass
));
1747 rescodes
[i
] = DSFXR_FAILED
;
1750 return DSERR_INVALIDPARAM
;
1753 static HRESULT WINAPI
DS8Buffer_AcquireResources(IDirectSoundBuffer8
*iface
, DWORD flags
, DWORD fxcount
, DWORD
*rescodes
)
1755 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1757 TRACE("(%p)->(%u, %u, %p)\n", This
, flags
, fxcount
, rescodes
);
1759 /* effects aren't supported at the moment.. */
1760 if(fxcount
!= 0 || rescodes
)
1762 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1763 return DSERR_INVALIDPARAM
;
1766 EnterCriticalSection(This
->crst
);
1767 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1769 This
->buffer
->dsbflags
&= ~(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
);
1770 if((flags
&DSBPLAY_LOCSOFTWARE
))
1771 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1773 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1775 LeaveCriticalSection(This
->crst
);
1780 static HRESULT WINAPI
DS8Buffer_GetObjectInPath(IDirectSoundBuffer8
*iface
, REFGUID guid
, DWORD idx
, REFGUID rguidiface
, void **ppv
)
1782 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface
, debugstr_guid(guid
), idx
, debugstr_guid(rguidiface
), ppv
);
1786 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
=
1788 DS8Buffer_QueryInterface
,
1792 DS8Buffer_GetCurrentPosition
,
1793 DS8Buffer_GetFormat
,
1794 DS8Buffer_GetVolume
,
1796 DS8Buffer_GetFrequency
,
1797 DS8Buffer_GetStatus
,
1798 DS8Buffer_Initialize
,
1801 DS8Buffer_SetCurrentPosition
,
1802 DS8Buffer_SetFormat
,
1803 DS8Buffer_SetVolume
,
1805 DS8Buffer_SetFrequency
,
1810 DS8Buffer_AcquireResources
,
1811 DS8Buffer_GetObjectInPath
1815 static HRESULT WINAPI
DS8Buffer3D_QueryInterface(IDirectSound3DBuffer
*iface
, REFIID riid
, void **ppv
)
1817 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1818 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1821 static ULONG WINAPI
DS8Buffer3D_AddRef(IDirectSound3DBuffer
*iface
)
1823 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1826 InterlockedIncrement(&This
->all_ref
);
1827 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1828 TRACE("new refcount %d\n", ret
);
1833 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1835 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1838 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1839 TRACE("new refcount %d\n", ret
);
1840 if(InterlockedDecrement(&This
->all_ref
) == 0)
1841 DS8Buffer_Destroy(This
);
1846 static HRESULT WINAPI
DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer
*iface
, DS3DBUFFER
*ds3dbuffer
)
1848 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1852 TRACE("%p\n", This
);
1854 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
1856 WARN("Invalid parameters %p %u\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
1857 return DSERR_INVALIDPARAM
;
1859 ds3dbuf
.dwSize
= sizeof(ds3dbuf
);
1861 EnterCriticalSection(This
->crst
);
1862 setALContext(This
->ctx
);
1864 hr
= IDirectSound3DBuffer_GetPosition(iface
, &ds3dbuf
.vPosition
);
1866 hr
= IDirectSound3DBuffer_GetVelocity(iface
, &ds3dbuf
.vVelocity
);
1868 hr
= IDirectSound3DBuffer_GetConeAngles(iface
, &ds3dbuf
.dwInsideConeAngle
, &ds3dbuf
.dwOutsideConeAngle
);
1870 hr
= IDirectSound3DBuffer_GetConeOrientation(iface
, &ds3dbuf
.vConeOrientation
);
1872 hr
= IDirectSound3DBuffer_GetConeOutsideVolume(iface
, &ds3dbuf
.lConeOutsideVolume
);
1874 hr
= IDirectSound3DBuffer_GetMinDistance(iface
, &ds3dbuf
.flMinDistance
);
1876 hr
= IDirectSound3DBuffer_GetMaxDistance(iface
, &ds3dbuf
.flMaxDistance
);
1878 hr
= IDirectSound3DBuffer_GetMode(iface
, &ds3dbuf
.dwMode
);
1880 memcpy(ds3dbuffer
, &ds3dbuf
, sizeof(ds3dbuf
));
1883 LeaveCriticalSection(This
->crst
);
1888 static HRESULT WINAPI
DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer
*iface
, DWORD
*pdwInsideConeAngle
, DWORD
*pdwOutsideConeAngle
)
1890 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1891 ALint inangle
, outangle
;
1893 TRACE("(%p)->(%p, %p)\n", This
, pdwInsideConeAngle
, pdwOutsideConeAngle
);
1894 if(!pdwInsideConeAngle
|| !pdwOutsideConeAngle
)
1896 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle
, pdwOutsideConeAngle
);
1897 return DSERR_INVALIDPARAM
;
1900 EnterCriticalSection(This
->crst
);
1901 setALContext(This
->ctx
);
1903 alGetSourcei(This
->source
, AL_CONE_INNER_ANGLE
, &inangle
);
1904 alGetSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, &outangle
);
1906 *pdwInsideConeAngle
= inangle
;
1907 *pdwOutsideConeAngle
= outangle
;
1910 LeaveCriticalSection(This
->crst
);
1915 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1917 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1920 TRACE("(%p)->(%p)\n", This
, orient
);
1923 WARN("Invalid pointer\n");
1924 return DSERR_INVALIDPARAM
;
1927 EnterCriticalSection(This
->crst
);
1928 setALContext(This
->ctx
);
1930 alGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1934 orient
->z
= -dir
[2];
1937 LeaveCriticalSection(This
->crst
);
1942 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1944 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1947 TRACE("(%p)->(%p)\n", This
, vol
);
1950 WARN("Invalid pointer\n");
1951 return DSERR_INVALIDPARAM
;
1954 EnterCriticalSection(This
->crst
);
1955 setALContext(This
->ctx
);
1957 alGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1959 *vol
= gain_to_mB(gain
);
1960 *vol
= max(*vol
, DSBVOLUME_MIN
);
1961 *vol
= min(*vol
, DSBVOLUME_MAX
);
1964 LeaveCriticalSection(This
->crst
);
1968 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1970 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1973 TRACE("(%p)->(%p)\n", This
, maxdist
);
1976 WARN("Invalid pointer\n");
1977 return DSERR_INVALIDPARAM
;
1980 EnterCriticalSection(This
->crst
);
1981 setALContext(This
->ctx
);
1983 alGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
1988 LeaveCriticalSection(This
->crst
);
1993 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
1995 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1998 TRACE("(%p)->(%p)\n", This
, mindist
);
2001 WARN("Invalid pointer\n");
2002 return DSERR_INVALIDPARAM
;
2005 EnterCriticalSection(This
->crst
);
2006 setALContext(This
->ctx
);
2008 alGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
2013 LeaveCriticalSection(This
->crst
);
2018 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
2020 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2022 TRACE("(%p)->(%p)\n", This
, mode
);
2025 WARN("Invalid pointer\n");
2026 return DSERR_INVALIDPARAM
;
2029 EnterCriticalSection(This
->crst
);
2030 *mode
= This
->ds3dmode
;
2031 LeaveCriticalSection(This
->crst
);
2036 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
2038 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2041 TRACE("(%p)->(%p)\n", This
, pos
);
2044 WARN("Invalid pointer\n");
2045 return DSERR_INVALIDPARAM
;
2048 EnterCriticalSection(This
->crst
);
2049 setALContext(This
->ctx
);
2051 alGetSourcefv(This
->source
, AL_POSITION
, alpos
);
2058 LeaveCriticalSection(This
->crst
);
2063 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
2065 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2068 TRACE("(%p)->(%p)\n", This
, vel
);
2071 WARN("Invalid pointer\n");
2072 return DSERR_INVALIDPARAM
;
2075 EnterCriticalSection(This
->crst
);
2076 setALContext(This
->ctx
);
2078 alGetSourcefv(This
->source
, AL_VELOCITY
, alvel
);
2085 LeaveCriticalSection(This
->crst
);
2090 static HRESULT WINAPI
DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer
*iface
, const DS3DBUFFER
*ds3dbuffer
, DWORD apply
)
2092 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2093 TRACE("(%p)->(%p, %u)\n", This
, ds3dbuffer
, apply
);
2095 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
2097 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
2098 return DSERR_INVALIDPARAM
;
2101 if(ds3dbuffer
->dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2102 ds3dbuffer
->dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2104 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer
->dwInsideConeAngle
,
2105 ds3dbuffer
->dwOutsideConeAngle
);
2106 return DSERR_INVALIDPARAM
;
2109 if(ds3dbuffer
->lConeOutsideVolume
> DSBVOLUME_MAX
||
2110 ds3dbuffer
->lConeOutsideVolume
< DSBVOLUME_MIN
)
2112 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer
->lConeOutsideVolume
);
2113 return DSERR_INVALIDPARAM
;
2116 if(ds3dbuffer
->flMaxDistance
< 0.0f
)
2118 WARN("Invalid max distance (%f)\n", ds3dbuffer
->flMaxDistance
);
2119 return DSERR_INVALIDPARAM
;
2122 if(ds3dbuffer
->flMinDistance
< 0.0f
)
2124 WARN("Invalid min distance (%f)\n", ds3dbuffer
->flMinDistance
);
2125 return DSERR_INVALIDPARAM
;
2128 if(ds3dbuffer
->dwMode
!= DS3DMODE_NORMAL
&&
2129 ds3dbuffer
->dwMode
!= DS3DMODE_HEADRELATIVE
&&
2130 ds3dbuffer
->dwMode
!= DS3DMODE_DISABLE
)
2132 WARN("Invalid mode (%u)\n", ds3dbuffer
->dwMode
);
2133 return DSERR_INVALIDPARAM
;
2136 EnterCriticalSection(This
->crst
);
2137 setALContext(This
->ctx
);
2138 IDirectSound3DBuffer_SetPosition(iface
, ds3dbuffer
->vPosition
.x
, ds3dbuffer
->vPosition
.y
, ds3dbuffer
->vPosition
.z
, apply
);
2139 IDirectSound3DBuffer_SetVelocity(iface
, ds3dbuffer
->vVelocity
.x
, ds3dbuffer
->vVelocity
.y
, ds3dbuffer
->vVelocity
.z
, apply
);
2140 IDirectSound3DBuffer_SetConeAngles(iface
, ds3dbuffer
->dwInsideConeAngle
, ds3dbuffer
->dwOutsideConeAngle
, apply
);
2141 IDirectSound3DBuffer_SetConeOrientation(iface
, ds3dbuffer
->vConeOrientation
.x
, ds3dbuffer
->vConeOrientation
.y
, ds3dbuffer
->vConeOrientation
.z
, apply
);
2142 IDirectSound3DBuffer_SetConeOutsideVolume(iface
, ds3dbuffer
->lConeOutsideVolume
, apply
);
2143 IDirectSound3DBuffer_SetMinDistance(iface
, ds3dbuffer
->flMinDistance
, apply
);
2144 IDirectSound3DBuffer_SetMaxDistance(iface
, ds3dbuffer
->flMaxDistance
, apply
);
2145 IDirectSound3DBuffer_SetMode(iface
, ds3dbuffer
->dwMode
, apply
);
2147 LeaveCriticalSection(This
->crst
);
2152 static HRESULT WINAPI
DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer
*iface
, DWORD dwInsideConeAngle
, DWORD dwOutsideConeAngle
, DWORD apply
)
2154 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2156 TRACE("(%p)->(%u, %u, %u)\n", This
, dwInsideConeAngle
, dwOutsideConeAngle
, apply
);
2157 if(dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2158 dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2160 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle
, dwOutsideConeAngle
);
2161 return DSERR_INVALIDPARAM
;
2164 EnterCriticalSection(This
->crst
);
2165 if(apply
== DS3D_DEFERRED
)
2167 This
->ds3dbuffer
.dwInsideConeAngle
= dwInsideConeAngle
;
2168 This
->ds3dbuffer
.dwOutsideConeAngle
= dwOutsideConeAngle
;
2169 This
->dirty
.bit
.cone_angles
= 1;
2173 setALContext(This
->ctx
);
2174 alSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
2175 alSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
2179 LeaveCriticalSection(This
->crst
);
2184 static HRESULT WINAPI
DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2186 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2188 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2190 EnterCriticalSection(This
->crst
);
2191 if(apply
== DS3D_DEFERRED
)
2193 This
->ds3dbuffer
.vConeOrientation
.x
= x
;
2194 This
->ds3dbuffer
.vConeOrientation
.y
= y
;
2195 This
->ds3dbuffer
.vConeOrientation
.z
= z
;
2196 This
->dirty
.bit
.cone_orient
= 1;
2200 setALContext(This
->ctx
);
2201 alSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
2205 LeaveCriticalSection(This
->crst
);
2210 static HRESULT WINAPI
DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG vol
, DWORD apply
)
2212 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2214 TRACE("(%p)->(%u, %u)\n", This
, vol
, apply
);
2215 if(vol
< DSBVOLUME_MIN
|| vol
> DSBVOLUME_MAX
)
2217 WARN("Invalid volume (%u)\n", vol
);
2218 return DSERR_INVALIDPARAM
;
2221 EnterCriticalSection(This
->crst
);
2222 if(apply
== DS3D_DEFERRED
)
2224 This
->ds3dbuffer
.lConeOutsideVolume
= vol
;
2225 This
->dirty
.bit
.cone_outsidevolume
= 1;
2229 setALContext(This
->ctx
);
2230 alSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
2234 LeaveCriticalSection(This
->crst
);
2239 static HRESULT WINAPI
DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE maxdist
, DWORD apply
)
2241 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2243 TRACE("(%p)->(%f, %u)\n", This
, maxdist
, apply
);
2246 WARN("Invalid max distance (%f)\n", maxdist
);
2247 return DSERR_INVALIDPARAM
;
2250 EnterCriticalSection(This
->crst
);
2251 if(apply
== DS3D_DEFERRED
)
2253 This
->ds3dbuffer
.flMaxDistance
= maxdist
;
2254 This
->dirty
.bit
.max_distance
= 1;
2258 setALContext(This
->ctx
);
2259 alSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
2263 LeaveCriticalSection(This
->crst
);
2268 static HRESULT WINAPI
DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE mindist
, DWORD apply
)
2270 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2272 TRACE("(%p)->(%f, %u)\n", This
, mindist
, apply
);
2275 WARN("Invalid min distance (%f)\n", mindist
);
2276 return DSERR_INVALIDPARAM
;
2279 EnterCriticalSection(This
->crst
);
2280 if(apply
== DS3D_DEFERRED
)
2282 This
->ds3dbuffer
.flMinDistance
= mindist
;
2283 This
->dirty
.bit
.min_distance
= 1;
2287 setALContext(This
->ctx
);
2288 alSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
2292 LeaveCriticalSection(This
->crst
);
2297 static HRESULT WINAPI
DS8Buffer3D_SetMode(IDirectSound3DBuffer
*iface
, DWORD mode
, DWORD apply
)
2299 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2301 TRACE("(%p)->(%u, %u)\n", This
, mode
, apply
);
2302 if(mode
!= DS3DMODE_NORMAL
&& mode
!= DS3DMODE_HEADRELATIVE
&&
2303 mode
!= DS3DMODE_DISABLE
)
2305 WARN("Invalid mode (%u)\n", mode
);
2306 return DSERR_INVALIDPARAM
;
2309 EnterCriticalSection(This
->crst
);
2310 if(apply
== DS3D_DEFERRED
)
2312 This
->ds3dbuffer
.dwMode
= mode
;
2313 This
->dirty
.bit
.mode
= 1;
2317 setALContext(This
->ctx
);
2318 alSourcei(This
->source
, AL_SOURCE_RELATIVE
,
2319 (mode
!= DS3DMODE_NORMAL
) ? AL_TRUE
: AL_FALSE
);
2320 alSourcef(This
->source
, AL_ROLLOFF_FACTOR
,
2321 (mode
== DS3DMODE_DISABLE
) ? 0.0f
: This
->primary
->rollofffactor
);
2322 This
->ds3dmode
= mode
;
2326 LeaveCriticalSection(This
->crst
);
2331 static HRESULT WINAPI
DS8Buffer3D_SetPosition(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2333 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2335 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2337 EnterCriticalSection(This
->crst
);
2338 if(apply
== DS3D_DEFERRED
)
2340 This
->ds3dbuffer
.vPosition
.x
= x
;
2341 This
->ds3dbuffer
.vPosition
.y
= y
;
2342 This
->ds3dbuffer
.vPosition
.z
= z
;
2343 This
->dirty
.bit
.pos
= 1;
2347 setALContext(This
->ctx
);
2348 alSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
2352 LeaveCriticalSection(This
->crst
);
2357 static HRESULT WINAPI
DS8Buffer3D_SetVelocity(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2359 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2361 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2363 EnterCriticalSection(This
->crst
);
2364 if(apply
== DS3D_DEFERRED
)
2366 This
->ds3dbuffer
.vVelocity
.x
= x
;
2367 This
->ds3dbuffer
.vVelocity
.y
= y
;
2368 This
->ds3dbuffer
.vVelocity
.z
= z
;
2369 This
->dirty
.bit
.vel
= 1;
2373 setALContext(This
->ctx
);
2374 alSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
2378 LeaveCriticalSection(This
->crst
);
2383 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2385 DS8Buffer3D_QueryInterface
,
2387 DS8Buffer3D_Release
,
2388 DS8Buffer3D_GetAllParameters
,
2389 DS8Buffer3D_GetConeAngles
,
2390 DS8Buffer3D_GetConeOrientation
,
2391 DS8Buffer3D_GetConeOutsideVolume
,
2392 DS8Buffer3D_GetMaxDistance
,
2393 DS8Buffer3D_GetMinDistance
,
2394 DS8Buffer3D_GetMode
,
2395 DS8Buffer3D_GetPosition
,
2396 DS8Buffer3D_GetVelocity
,
2397 DS8Buffer3D_SetAllParameters
,
2398 DS8Buffer3D_SetConeAngles
,
2399 DS8Buffer3D_SetConeOrientation
,
2400 DS8Buffer3D_SetConeOutsideVolume
,
2401 DS8Buffer3D_SetMaxDistance
,
2402 DS8Buffer3D_SetMinDistance
,
2403 DS8Buffer3D_SetMode
,
2404 DS8Buffer3D_SetPosition
,
2405 DS8Buffer3D_SetVelocity
2409 static HRESULT WINAPI
DS8BufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
2411 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2412 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2415 static ULONG WINAPI
DS8BufferNot_AddRef(IDirectSoundNotify
*iface
)
2417 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2420 InterlockedIncrement(&This
->all_ref
);
2421 ret
= InterlockedIncrement(&This
->not_ref
);
2422 TRACE("new refcount %d\n", ret
);
2427 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2429 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2432 ret
= InterlockedDecrement(&This
->not_ref
);
2433 TRACE("new refcount %d\n", ret
);
2434 if(InterlockedDecrement(&This
->all_ref
) == 0)
2435 DS8Buffer_Destroy(This
);
2440 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2442 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2443 DSBPOSITIONNOTIFY
*nots
;
2447 EnterCriticalSection(This
->crst
);
2448 hr
= DSERR_INVALIDPARAM
;
2449 if(count
&& !notifications
)
2452 hr
= IDirectSoundBuffer8_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2456 hr
= DSERR_INVALIDCALL
;
2457 if((state
&DSBSTATUS_PLAYING
))
2462 HeapFree(GetProcessHeap(), 0, This
->notify
);
2471 hr
= DSERR_INVALIDPARAM
;
2472 for(i
= 0;i
< count
;++i
)
2474 if(notifications
[i
].dwOffset
>= This
->buffer
->buf_size
&&
2475 notifications
[i
].dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
2480 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2483 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2485 HeapFree(GetProcessHeap(), 0, This
->notify
);
2486 This
->notify
= nots
;
2487 This
->nnotify
= count
;
2493 LeaveCriticalSection(This
->crst
);
2497 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
=
2499 DS8BufferNot_QueryInterface
,
2500 DS8BufferNot_AddRef
,
2501 DS8BufferNot_Release
,
2502 DS8BufferNot_SetNotificationPositions
2506 static HRESULT WINAPI
DS8BufferProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
2508 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2509 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2512 static ULONG WINAPI
DS8BufferProp_AddRef(IKsPropertySet
*iface
)
2514 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2517 InterlockedIncrement(&This
->all_ref
);
2518 ret
= InterlockedIncrement(&This
->prop_ref
);
2519 TRACE("new refcount %d\n", ret
);
2524 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2526 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2529 ret
= InterlockedDecrement(&This
->prop_ref
);
2530 TRACE("new refcount %d\n", ret
);
2531 if(InterlockedDecrement(&This
->all_ref
) == 0)
2532 DS8Buffer_Destroy(This
);
2537 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2538 handled through secondary buffers. */
2539 static HRESULT WINAPI
DS8BufferProp_Get(IKsPropertySet
*iface
,
2540 REFGUID guidPropSet
, ULONG dwPropID
,
2541 LPVOID pInstanceData
, ULONG cbInstanceData
,
2542 LPVOID pPropData
, ULONG cbPropData
,
2545 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2546 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2548 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface
, debugstr_guid(guidPropSet
),
2549 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
2556 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2562 /* Not a known buffer/source property. Pass it to the listener */
2563 hr
= IKsPropertySet_Get(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2564 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
,
2571 static HRESULT WINAPI
DS8BufferProp_Set(IKsPropertySet
*iface
,
2572 REFGUID guidPropSet
, ULONG dwPropID
,
2573 LPVOID pInstanceData
, ULONG cbInstanceData
,
2574 LPVOID pPropData
, ULONG cbPropData
)
2576 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2577 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2579 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface
, debugstr_guid(guidPropSet
),
2580 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
2583 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2589 /* Not a known buffer/source property. Pass it to the listener */
2590 hr
= IKsPropertySet_Set(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2591 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
,
2598 static HRESULT WINAPI
DS8BufferProp_QuerySupport(IKsPropertySet
*iface
,
2599 REFGUID guidPropSet
, ULONG dwPropID
,
2600 PULONG pTypeSupport
)
2602 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2603 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2605 TRACE("(%p)->(%s, %u, %p)\n", iface
, debugstr_guid(guidPropSet
), dwPropID
, pTypeSupport
);
2612 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2618 /* Not a known buffer/source property. Pass it to the listener */
2619 hr
= IKsPropertySet_QuerySupport(&This
->primary
->IKsPropertySet_iface
,
2620 guidPropSet
, dwPropID
, pTypeSupport
);
2626 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2628 DS8BufferProp_QueryInterface
,
2629 DS8BufferProp_AddRef
,
2630 DS8BufferProp_Release
,
2633 DS8BufferProp_QuerySupport