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 void CALLBACK
DS8Buffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
85 DWORD_PTR dw1
, DWORD_PTR dw2
)
91 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
94 static void DS8Buffer_starttimer(DS8Primary
*prim
)
96 DWORD triggertime
, res
= DS_TIME_RES
;
97 ALint refresh
= FAKE_REFRESH_COUNT
;
103 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
105 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
106 getALCError(prim
->parent
->device
);
108 triggertime
= 1000 / refresh
/ 2;
109 if(triggertime
< time
.wPeriodMin
)
110 triggertime
= time
.wPeriodMin
;
111 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime
, refresh
);
113 if (res
< time
.wPeriodMin
)
114 res
= time
.wPeriodMin
;
115 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
116 WARN("Could not set minimum resolution, don't expect sound\n");
118 prim
->timer_res
= res
;
119 prim
->timer_id
= timeSetEvent(triggertime
, res
, DS8Buffer_timer
, prim
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
122 /* Should be called with critsect held and context set.. */
123 static void DS8Buffer_addnotify(DS8Buffer
*buf
)
128 list
= buf
->primary
->notifies
;
129 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
133 ERR("Buffer %p already in notification list\n", buf
);
137 if(buf
->primary
->nnotifies
== buf
->primary
->sizenotifies
)
139 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (buf
->primary
->nnotifies
+ 1) * sizeof(*list
));
142 buf
->primary
->sizenotifies
++;
144 list
[buf
->primary
->nnotifies
++] = buf
;
145 buf
->primary
->notifies
= list
;
149 static const char *get_fmtstr_PCM(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
151 out
->Format
= *format
;
152 out
->Format
.cbSize
= 0;
154 if(format
->wBitsPerSample
== 8)
156 *in_type
= AL_UNSIGNED_BYTE
;
157 switch(format
->nChannels
)
159 case 1: *in_chans
= AL_MONO
;
160 return "AL_FORMAT_MONO8";
161 case 2: *in_chans
= AL_STEREO
;
162 return "AL_FORMAT_STEREO8";
163 case 4: *in_chans
= AL_QUAD
;
164 return "AL_FORMAT_QUAD8";
165 case 6: *in_chans
= AL_5POINT1
;
166 return "AL_FORMAT_51CHN8";
167 case 7: *in_chans
= AL_6POINT1
;
168 return "AL_FORMAT_61CHN8";
169 case 8: *in_chans
= AL_7POINT1
;
170 return "AL_FORMAT_71CHN8";
174 else if(format
->wBitsPerSample
== 16)
177 switch(format
->nChannels
)
179 case 1: *in_chans
= AL_MONO
;
180 return "AL_FORMAT_MONO16";
181 case 2: *in_chans
= AL_STEREO
;
182 return "AL_FORMAT_STEREO16";
183 case 4: *in_chans
= AL_QUAD
;
184 return "AL_FORMAT_QUAD16";
185 case 6: *in_chans
= AL_5POINT1
;
186 return "AL_FORMAT_51CHN16";
187 case 7: *in_chans
= AL_6POINT1
;
188 return "AL_FORMAT_61CHN16";
189 case 8: *in_chans
= AL_7POINT1
;
190 return "AL_FORMAT_71CHN16";
194 #if 0 /* Will cause incorrect byte offsets */
195 else if(format
->wBitsPerSample
== 24 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
198 switch(format
->nChannels
)
200 case 1: *in_chans
= AL_MONO
;
202 case 2: *in_chans
= AL_STEREO
;
203 return "AL_STEREO32F";
204 case 4: *in_chans
= AL_QUAD
;
206 case 6: *in_chans
= AL_5POINT1
;
207 return "AL_5POINT1_32F";
208 case 7: *in_chans
= AL_6POINT1
;
209 return "AL_6POINT1_32F";
210 case 8: *in_chans
= AL_7POINT1
;
211 return "AL_7POINT1_32F";
216 else if(format
->wBitsPerSample
== 32 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
219 switch(format
->nChannels
)
221 case 1: *in_chans
= AL_MONO
;
223 case 2: *in_chans
= AL_STEREO
;
224 return "AL_STEREO32F";
225 case 4: *in_chans
= AL_QUAD
;
227 case 6: *in_chans
= AL_5POINT1
;
228 return "AL_5POINT1_32F";
229 case 7: *in_chans
= AL_6POINT1
;
230 return "AL_6POINT1_32F";
231 case 8: *in_chans
= AL_7POINT1
;
232 return "AL_7POINT1_32F";
237 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
238 format
->wBitsPerSample
, format
->nChannels
);
242 static const char *get_fmtstr_FLOAT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
244 out
->Format
= *format
;
245 out
->Format
.cbSize
= 0;
247 if(format
->wBitsPerSample
== 32 &&
248 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
251 switch(format
->nChannels
)
253 case 1: *in_chans
= AL_MONO
;
254 return "AL_FORMAT_MONO_FLOAT32";
255 case 2: *in_chans
= AL_STEREO
;
256 return "AL_FORMAT_STEREO_FLOAT32";
257 case 4: *in_chans
= AL_QUAD
;
258 return "AL_FORMAT_QUAD32";
259 case 6: *in_chans
= AL_5POINT1
;
260 return "AL_FORMAT_51CHN32";
261 case 7: *in_chans
= AL_6POINT1
;
262 return "AL_FORMAT_61CHN32";
263 case 8: *in_chans
= AL_7POINT1
;
264 return "AL_FORMAT_71CHN32";
268 #if 0 /* Will cause incorrect byte offsets */
269 else if(format
->wBitsPerSample
== 64 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
271 *in_type
= AL_DOUBLE
;
272 switch(format
->nChannels
)
274 case 1: *in_chans
= AL_MONO
;
276 case 2: *in_chans
= AL_STEREO
;
277 return "AL_STEREO32F";
278 case 4: *in_chans
= AL_QUAD
;
280 case 6: *in_chans
= AL_5POINT1
;
281 return "AL_5POINT1_32F";
282 case 7: *in_chans
= AL_6POINT1
;
283 return "AL_6POINT1_32F";
284 case 8: *in_chans
= AL_7POINT1
;
285 return "AL_7POINT1_32F";
291 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
292 format
->wBitsPerSample
, format
->nChannels
);
296 /* Speaker configs */
297 #define MONO SPEAKER_FRONT_CENTER
298 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
299 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
300 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
301 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
302 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
303 #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)
305 static const char *get_fmtstr_EXT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
307 *out
= *(const WAVEFORMATEXTENSIBLE
*)format
;
308 out
->Format
.cbSize
= sizeof(*out
) - sizeof(out
->Format
);
310 if(!out
->Samples
.wValidBitsPerSample
)
311 out
->Samples
.wValidBitsPerSample
= out
->Format
.wBitsPerSample
;
312 else if(out
->Samples
.wValidBitsPerSample
!= out
->Format
.wBitsPerSample
)
314 FIXME("Padded samples not supported (%u of %u)\n", out
->Samples
.wValidBitsPerSample
, out
->Format
.wBitsPerSample
);
318 if(out
->dwChannelMask
!= MONO
&& out
->dwChannelMask
!= STEREO
&&
319 !prim
->SupportedExt
[EXT_MCFORMATS
] && !prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
321 WARN("Multi-channel not available\n");
325 if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
327 if(out
->Samples
.wValidBitsPerSample
== 8)
329 *in_type
= AL_UNSIGNED_BYTE
;
330 switch(out
->dwChannelMask
)
332 case MONO
: *in_chans
= AL_MONO
;
333 return "AL_FORMAT_MONO8";
334 case STEREO
: *in_chans
= AL_STEREO
;
335 return "AL_FORMAT_STEREO8";
336 case REAR
: *in_chans
= AL_REAR
;
337 return "AL_FORMAT_REAR8";
338 case QUAD
: *in_chans
= AL_QUAD
;
339 return "AL_FORMAT_QUAD8";
340 case X5DOT1
: *in_chans
= AL_5POINT1
;
341 return "AL_FORMAT_51CHN8";
342 case X6DOT1
: *in_chans
= AL_6POINT1
;
343 return "AL_FORMAT_61CHN8";
344 case X7DOT1
: *in_chans
= AL_7POINT1
;
345 return "AL_FORMAT_71CHN8";
349 else if(out
->Samples
.wValidBitsPerSample
== 16)
352 switch(out
->dwChannelMask
)
354 case MONO
: *in_chans
= AL_MONO
;
355 return "AL_FORMAT_MONO16";
356 case STEREO
: *in_chans
= AL_STEREO
;
357 return "AL_FORMAT_STEREO16";
358 case REAR
: *in_chans
= AL_REAR
;
359 return "AL_FORMAT_REAR16";
360 case QUAD
: *in_chans
= AL_QUAD
;
361 return "AL_FORMAT_QUAD16";
362 case X5DOT1
: *in_chans
= AL_5POINT1
;
363 return "AL_FORMAT_51CHN16";
364 case X6DOT1
: *in_chans
= AL_6POINT1
;
365 return "AL_FORMAT_61CHN16";
366 case X7DOT1
: *in_chans
= AL_7POINT1
;
367 return "AL_FORMAT_71CHN16";
372 else if(out
->Samples
.wValidBitsPerSample
== 24 &&
373 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
376 switch(out
->dwChannelMask
)
378 case MONO
: *in_chans
= AL_MONO
;
380 case STEREO
: *in_chans
= AL_STEREO
;
381 return "AL_STEREO32F";
382 case REAR
: *in_chans
= AL_REAR
;
384 case QUAD
: *in_chans
= AL_QUAD
;
386 case X5DOT1
: *in_chans
= AL_5POINT1
;
387 return "AL_5POINT1_32F";
388 case X6DOT1
: *in_chans
= AL_6POINT1
;
389 return "AL_6POINT1_32F";
390 case X7DOT1
: *in_chans
= AL_7POINT1
;
391 return "AL_7POINT1_32F";
396 else if(out
->Samples
.wValidBitsPerSample
== 32 &&
397 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
400 switch(out
->dwChannelMask
)
402 case MONO
: *in_chans
= AL_MONO
;
404 case STEREO
: *in_chans
= AL_STEREO
;
405 return "AL_STEREO32F";
406 case REAR
: *in_chans
= AL_REAR
;
408 case QUAD
: *in_chans
= AL_QUAD
;
410 case X5DOT1
: *in_chans
= AL_5POINT1
;
411 return "AL_5POINT1_32F";
412 case X6DOT1
: *in_chans
= AL_6POINT1
;
413 return "AL_6POINT1_32F";
414 case X7DOT1
: *in_chans
= AL_7POINT1
;
415 return "AL_7POINT1_32F";
420 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
421 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
424 else if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
425 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
427 if(out
->Samples
.wValidBitsPerSample
== 32)
430 switch(out
->dwChannelMask
)
432 case MONO
: *in_chans
= AL_MONO
;
433 return "AL_FORMAT_MONO_FLOAT32";
434 case STEREO
: *in_chans
= AL_STEREO
;
435 return "AL_FORMAT_STEREO_FLOAT32";
436 case REAR
: *in_chans
= AL_REAR
;
437 return "AL_FORMAT_REAR32";
438 case QUAD
: *in_chans
= AL_QUAD
;
439 return "AL_FORMAT_QUAD32";
440 case X5DOT1
: *in_chans
= AL_5POINT1
;
441 return "AL_FORMAT_51CHN32";
442 case X6DOT1
: *in_chans
= AL_6POINT1
;
443 return "AL_FORMAT_61CHN32";
444 case X7DOT1
: *in_chans
= AL_7POINT1
;
445 return "AL_FORMAT_71CHN32";
450 else if(out
->Samples
.wValidBitsPerSample
== 64 &&
451 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
453 *in_type
= AL_DOUBLE
;
454 switch(out
->dwChannelMask
)
456 case MONO
: *in_chans
= AL_MONO
;
458 case STEREO
: *in_chans
= AL_STEREO
;
459 return "AL_STEREO32F";
460 case REAR
: *in_chans
= AL_REAR
;
462 case QUAD
: *in_chans
= AL_QUAD
;
464 case X5DOT1
: *in_chans
= AL_5POINT1
;
465 return "AL_5POINT1_32F";
466 case X6DOT1
: *in_chans
= AL_6POINT1
;
467 return "AL_6POINT1_32F";
468 case X7DOT1
: *in_chans
= AL_7POINT1
;
469 return "AL_7POINT1_32F";
476 WARN("Invalid float bits: %u\n", out
->Samples
.wValidBitsPerSample
);
480 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
481 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
484 else if(!IsEqualGUID(&out
->SubFormat
, &GUID_NULL
))
485 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out
->SubFormat
));
489 static void DS8Data_Release(DS8Data
*This
);
490 static HRESULT
DS8Data_Create(DS8Data
**ppv
, const DSBUFFERDESC
*desc
, DS8Primary
*prim
)
492 HRESULT hr
= DSERR_INVALIDPARAM
;
493 const WAVEFORMATEX
*format
;
494 const char *fmt_str
= NULL
;
497 format
= desc
->lpwfxFormat
;
498 TRACE("Requested buffer format:\n"
499 " FormatTag = 0x%04x\n"
501 " SamplesPerSec = %u\n"
502 " AvgBytesPerSec = %u\n"
504 " BitsPerSample = %d\n",
505 format
->wFormatTag
, format
->nChannels
,
506 format
->nSamplesPerSec
, format
->nAvgBytesPerSec
,
507 format
->nBlockAlign
, format
->wBitsPerSample
);
509 if(format
->nBlockAlign
== 0)
511 WARN("Invalid BlockAlign specified\n");
512 return DSERR_INVALIDPARAM
;
515 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
516 * will need the EAX-RAM extension. Currently, we just tell the app it
517 * gets what it wanted. */
518 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
520 return E_OUTOFMEMORY
;
523 pBuffer
->dsbflags
= desc
->dwFlags
;
524 if((pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
)) == (DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
))
526 WARN("Hardware and software location requested\n");
529 if(!(pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCDEFER
)))
530 pBuffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
532 pBuffer
->buf_size
= desc
->dwBufferBytes
+ format
->nBlockAlign
- 1;
533 pBuffer
->buf_size
-= pBuffer
->buf_size
%format
->nBlockAlign
;
535 hr
= DSERR_BUFFERTOOSMALL
;
536 if(pBuffer
->buf_size
< DSBSIZE_MIN
)
539 hr
= DSERR_INVALIDPARAM
;
540 if(pBuffer
->buf_size
> DSBSIZE_MAX
)
543 pBuffer
->numsegs
= 1;
544 pBuffer
->segsize
= pBuffer
->buf_size
;
545 pBuffer
->lastsegsize
= pBuffer
->buf_size
;
547 if(!(pBuffer
->dsbflags
&DSBCAPS_STATIC
) && !prim
->ExtAL
.BufferSubData
&&
548 !prim
->ExtAL
.BufferSamplesSOFT
&& !prim
->ExtAL
.BufferDataStatic
)
550 ALCint refresh
= FAKE_REFRESH_COUNT
;
553 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
554 getALCError(prim
->parent
->device
);
556 newSize
= format
->nAvgBytesPerSec
/refresh
+ format
->nBlockAlign
- 1;
557 newSize
-= newSize
%format
->nBlockAlign
;
559 /* Make sure enough buffers are available */
560 if(newSize
> pBuffer
->buf_size
/(QBUFFERS
+2))
561 ERR("Buffer segments too large to stream (%u for %u)!\n",
562 newSize
, pBuffer
->buf_size
);
565 pBuffer
->numsegs
= pBuffer
->buf_size
/newSize
;
566 pBuffer
->segsize
= newSize
;
567 pBuffer
->lastsegsize
= pBuffer
->buf_size
- (newSize
*(pBuffer
->numsegs
-1));
568 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
569 pBuffer
->numsegs
, pBuffer
->segsize
, pBuffer
->lastsegsize
);
573 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
574 fmt_str
= get_fmtstr_PCM(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
575 else if(format
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
576 fmt_str
= get_fmtstr_FLOAT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
577 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
579 const WAVEFORMATEXTENSIBLE
*wfe
;
581 hr
= DSERR_CONTROLUNAVAIL
;
582 if(format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
583 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
586 wfe
= (const WAVEFORMATEXTENSIBLE
*)format
;
587 TRACE("Extensible values:\n"
589 " ChannelMask = %#x\n"
591 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
592 debugstr_guid(&wfe
->SubFormat
));
594 hr
= DSERR_INVALIDCALL
;
595 fmt_str
= get_fmtstr_EXT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
598 ERR("Unhandled formattag 0x%04x\n", format
->wFormatTag
);
603 pBuffer
->buf_format
= alGetEnumValue(fmt_str
);
604 if(alGetError() != AL_NO_ERROR
|| pBuffer
->buf_format
== 0 ||
605 pBuffer
->buf_format
== -1)
607 WARN("Could not get OpenAL format from %s\n", fmt_str
);
612 pBuffer
->buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
->buffers
)*pBuffer
->numsegs
);
613 pBuffer
->data
= HeapAlloc(GetProcessHeap(), 0, pBuffer
->buf_size
);
614 if(!pBuffer
->buffers
|| !pBuffer
->data
)
617 alGenBuffers(pBuffer
->numsegs
, pBuffer
->buffers
);
624 DS8Data_Release(pBuffer
);
628 static void DS8Data_AddRef(DS8Data
*data
)
630 InterlockedIncrement(&data
->ref
);
633 /* This function is always called with the device lock held */
634 static void DS8Data_Release(DS8Data
*This
)
636 if(InterlockedDecrement(&This
->ref
)) return;
638 TRACE("Deleting %p\n", This
);
639 if (This
->buffers
&& This
->buffers
[0])
641 alDeleteBuffers(This
->numsegs
, This
->buffers
);
644 HeapFree(GetProcessHeap(), 0, This
->buffers
);
645 HeapFree(GetProcessHeap(), 0, This
->data
);
646 HeapFree(GetProcessHeap(), 0, This
);
649 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*parent
, DS8Buffer
*orig
)
651 HRESULT hr
= DSERR_OUTOFMEMORY
;
656 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
659 This
->IDirectSoundBuffer8_iface
.lpVtbl
= (IDirectSoundBuffer8Vtbl
*)&DS8Buffer_Vtbl
;
660 This
->IDirectSound3DBuffer_iface
.lpVtbl
= (IDirectSound3DBufferVtbl
*)&DS8Buffer3d_Vtbl
;
661 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DS8BufferNot_Vtbl
;
662 This
->IKsPropertySet_iface
.lpVtbl
= (IKsPropertySetVtbl
*)&DS8BufferProp_Vtbl
;
664 This
->primary
= parent
;
665 This
->ctx
= parent
->ctx
;
666 This
->ExtAL
= &parent
->ExtAL
;
667 This
->crst
= &parent
->crst
;
668 This
->ref
= This
->all_ref
= 1;
672 This
->buffer
= orig
->buffer
;
673 DS8Data_AddRef(This
->buffer
);
676 /* Append to buffer list */
677 bufs
= parent
->buffers
;
678 if(parent
->nbuffers
== parent
->sizebuffers
)
680 bufs
= HeapReAlloc(GetProcessHeap(), 0, bufs
, sizeof(*bufs
)*(1+parent
->nbuffers
));
682 parent
->sizebuffers
++;
684 parent
->buffers
= bufs
;
685 bufs
[parent
->nbuffers
++] = This
;
687 /* Disable until initialized.. */
688 This
->ds3dmode
= DS3DMODE_DISABLE
;
694 DS8Buffer_Destroy(This
);
698 void DS8Buffer_Destroy(DS8Buffer
*This
)
700 DS8Primary
*prim
= This
->primary
;
703 TRACE("Destroying %p\n", This
);
705 EnterCriticalSection(&prim
->crst
);
706 /* Remove from list, if in list */
707 for(idx
= 0;idx
< prim
->nnotifies
;++idx
)
709 if(This
== prim
->notifies
[idx
])
711 prim
->notifies
[idx
] = prim
->notifies
[--prim
->nnotifies
];
715 for(idx
= 0;idx
< prim
->nbuffers
;++idx
)
717 if(prim
->buffers
[idx
] == This
)
719 prim
->buffers
[idx
] = prim
->buffers
[--prim
->nbuffers
];
724 setALContext(This
->ctx
);
729 alSourceStop(This
->source
);
730 alSourcei(This
->source
, AL_BUFFER
, 0);
733 sources
= prim
->sources
;
734 if(prim
->nsources
== prim
->sizesources
)
736 sources
= HeapReAlloc(GetProcessHeap(), 0, sources
, sizeof(*sources
)*(prim
->nsources
+1));
738 alDeleteSources(1, &This
->source
);
744 sources
[prim
->nsources
++] = This
->source
;
745 prim
->sources
= sources
;
749 LeaveCriticalSection(&prim
->crst
);
752 DS8Data_Release(This
->buffer
);
756 HeapFree(GetProcessHeap(), 0, This
->notify
);
757 HeapFree(GetProcessHeap(), 0, This
);
760 static inline DS8Buffer
*impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8
*iface
)
762 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundBuffer8_iface
);
765 static HRESULT WINAPI
DS8Buffer_QueryInterface(IDirectSoundBuffer8
*iface
, REFIID riid
, void **ppv
)
767 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
769 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
772 if(IsEqualIID(riid
, &IID_IUnknown
) ||
773 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
774 *ppv
= &This
->IDirectSoundBuffer8_iface
;
775 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer8
))
777 if(This
->primary
->parent
->is_8
)
778 *ppv
= &This
->IDirectSoundBuffer8_iface
;
780 else if(IsEqualIID(riid
, &IID_IDirectSound3DBuffer
))
782 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
783 *ppv
= &This
->IDirectSound3DBuffer_iface
;
785 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
787 if((This
->buffer
->dsbflags
&DSBCAPS_CTRLPOSITIONNOTIFY
))
788 *ppv
= &This
->IDirectSoundNotify_iface
;
790 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
791 *ppv
= &This
->IKsPropertySet_iface
;
793 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
797 IUnknown_AddRef((IUnknown
*)*ppv
);
801 return E_NOINTERFACE
;
804 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
806 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
809 InterlockedIncrement(&This
->all_ref
);
810 ret
= InterlockedIncrement(&This
->ref
);
811 TRACE("new refcount %d\n", ret
);
816 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
818 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
821 ret
= InterlockedDecrement(&This
->ref
);
822 TRACE("new refcount %d\n", ret
);
823 if(InterlockedDecrement(&This
->all_ref
) == 0)
824 DS8Buffer_Destroy(This
);
829 static HRESULT WINAPI
DS8Buffer_GetCaps(IDirectSoundBuffer8
*iface
, DSBCAPS
*caps
)
831 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
833 TRACE("(%p)->(%p)\n", iface
, caps
);
835 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
837 WARN("Invalid DSBCAPS (%p, %u)\n", caps
, (caps
? caps
->dwSize
: 0));
838 return DSERR_INVALIDPARAM
;
841 caps
->dwFlags
= This
->buffer
->dsbflags
;
842 caps
->dwBufferBytes
= This
->buffer
->buf_size
;
843 caps
->dwUnlockTransferRate
= 4096;
844 caps
->dwPlayCpuOverhead
= 0;
848 static HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
850 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
851 WAVEFORMATEX
*format
= &This
->buffer
->format
.Format
;
852 UINT writecursor
, pos
;
854 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
856 EnterCriticalSection(This
->crst
);
857 setALContext(This
->ctx
);
859 if(This
->buffer
->numsegs
> 1)
861 ALint queued
= QBUFFERS
;
862 alGetSourcei(This
->source
, AL_BUFFERS_QUEUED
, &queued
);
865 pos
= (This
->curidx
+This
->buffer
->numsegs
-queued
)%This
->buffer
->numsegs
;
866 pos
*= This
->buffer
->segsize
;
867 writecursor
= This
->curidx
* This
->buffer
->segsize
;
869 else if(This
->ExtAL
->BufferSubData
|| This
->ExtAL
->BufferSamplesSOFT
)
871 ALint rwpos
[2] = { 0, 0 };
873 alGetSourceiv(This
->source
, AL_BYTE_RW_OFFSETS_SOFT
, rwpos
);
877 writecursor
= rwpos
[1];
884 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
885 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
889 if(status
== AL_PLAYING
)
891 writecursor
= format
->nSamplesPerSec
/ 100;
892 writecursor
*= format
->nBlockAlign
;
896 writecursor
= (writecursor
+ pos
) % This
->buffer
->buf_size
;
898 TRACE("%p Play pos = %u, write pos = %u\n", This
, pos
, writecursor
);
899 if(pos
>= This
->buffer
->buf_size
)
901 ERR("playpos >= buf_size\n");
902 pos
%= This
->buffer
->buf_size
;
904 if(writecursor
>= This
->buffer
->buf_size
)
906 ERR("writepos >= buf_size\n");
907 writecursor
%= This
->buffer
->buf_size
;
910 if(playpos
) *playpos
= pos
;
911 if(curpos
) *curpos
= writecursor
;
914 LeaveCriticalSection(This
->crst
);
919 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
921 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
925 TRACE("(%p)->(%p, %u, %p)\n", iface
, wfx
, allocated
, written
);
929 WARN("Cannot report format or format size\n");
930 return DSERR_INVALIDPARAM
;
933 EnterCriticalSection(This
->crst
);
934 size
= sizeof(This
->buffer
->format
.Format
) + This
->buffer
->format
.Format
.cbSize
;
938 hr
= DSERR_INVALIDPARAM
;
940 memcpy(wfx
, &This
->buffer
->format
.Format
, size
);
944 LeaveCriticalSection(This
->crst
);
949 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
951 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
954 TRACE("(%p)->(%p)\n", iface
, vol
);
958 WARN("Invalid pointer\n");
959 return DSERR_INVALIDPARAM
;
962 EnterCriticalSection(This
->crst
);
964 hr
= DSERR_CONTROLUNAVAIL
;
965 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
966 WARN("Volume control not set\n");
971 setALContext(This
->ctx
);
972 alGetSourcef(This
->source
, AL_GAIN
, &gain
);
976 *vol
= gain_to_mB(gain
);
977 *vol
= min(*vol
, DSBVOLUME_MAX
);
978 *vol
= max(*vol
, DSBVOLUME_MIN
);
983 LeaveCriticalSection(This
->crst
);
987 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
989 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
992 TRACE("(%p)->(%p)\n", iface
, pan
);
996 WARN("Invalid pointer\n");
997 return DSERR_INVALIDPARAM
;
1000 EnterCriticalSection(This
->crst
);
1002 hr
= DSERR_CONTROLUNAVAIL
;
1003 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1004 WARN("Panning control not set\n");
1009 setALContext(This
->ctx
);
1010 alGetSourcefv(This
->source
, AL_POSITION
, pos
);
1014 *pan
= (LONG
)((pos
[0]+1.0) * (DSBPAN_RIGHT
-DSBPAN_LEFT
) / 2.0 + 0.5) + DSBPAN_LEFT
;
1015 *pan
= min(*pan
, DSBPAN_RIGHT
);
1016 *pan
= max(*pan
, DSBPAN_LEFT
);
1021 LeaveCriticalSection(This
->crst
);
1025 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
1027 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1030 TRACE("(%p)->(%p)\n", iface
, freq
);
1034 WARN("Invalid pointer\n");
1035 return DSERR_INVALIDPARAM
;
1038 EnterCriticalSection(This
->crst
);
1040 hr
= DSERR_CONTROLUNAVAIL
;
1041 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1042 WARN("Frequency control not set\n");
1045 ALfloat pitch
= 1.0f
;
1047 setALContext(This
->ctx
);
1048 alGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
1052 *freq
= (DWORD
)(This
->buffer
->format
.Format
.nSamplesPerSec
* pitch
);
1057 LeaveCriticalSection(This
->crst
);
1061 static HRESULT WINAPI
DS8Buffer_GetStatus(IDirectSoundBuffer8
*iface
, DWORD
*status
)
1063 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1064 ALint state
, looping
;
1066 TRACE("(%p)->(%p)\n", iface
, status
);
1070 WARN("Invalid pointer\n");
1071 return DSERR_INVALIDPARAM
;
1074 EnterCriticalSection(This
->crst
);
1076 setALContext(This
->ctx
);
1077 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1078 looping
= This
->islooping
;
1079 if(This
->buffer
->numsegs
== 1)
1080 alGetSourcei(This
->source
, AL_LOOPING
, &looping
);
1081 else if(state
!= AL_PLAYING
)
1082 state
= This
->isplaying
? AL_PLAYING
: AL_PAUSED
;
1087 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1089 if((This
->buffer
->dsbflags
&DSBCAPS_LOCSOFTWARE
))
1090 *status
|= DSBSTATUS_LOCSOFTWARE
;
1091 else if((This
->buffer
->dsbflags
&DSBCAPS_LOCHARDWARE
))
1092 *status
|= DSBSTATUS_LOCHARDWARE
;
1094 if(state
== AL_PLAYING
)
1095 *status
|= DSBSTATUS_PLAYING
| (looping
? DSBSTATUS_LOOPING
: 0);
1097 LeaveCriticalSection(This
->crst
);
1102 static HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
1104 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1105 DS3DBUFFER
*ds3dbuffer
;
1108 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
1110 EnterCriticalSection(This
->crst
);
1111 setALContext(This
->ctx
);
1113 hr
= DSERR_ALREADYINITIALIZED
;
1119 hr
= DSERR_INVALIDPARAM
;
1122 WARN("Missing DSound buffer description\n");
1125 if(!desc
->lpwfxFormat
)
1127 WARN("Missing buffer format (%p)\n", This
);
1130 if((desc
->dwFlags
&DSBCAPS_CTRL3D
) && desc
->lpwfxFormat
->nChannels
!= 1)
1132 if(This
->primary
->parent
->is_8
)
1134 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1136 WARN("Can't create multi-channel 3D buffers\n");
1139 ERR("Multi-channel 3D sounds are not spatialized\n");
1142 hr
= DS8Data_Create(&This
->buffer
, desc
, This
->primary
);
1147 DS8Data
*buf
= This
->buffer
;
1149 if(buf
->in_type
== AL_UNSIGNED_BYTE
)
1150 memset(buf
->data
, 0x80, buf
->buf_size
);
1152 memset(buf
->data
, 0x00, buf
->buf_size
);
1154 if(This
->ExtAL
->BufferDataStatic
)
1155 This
->ExtAL
->BufferDataStatic(buf
->buffers
[0], buf
->buf_format
,
1156 buf
->data
, buf
->buf_size
,
1157 buf
->format
.Format
.nSamplesPerSec
);
1158 else if(This
->ExtAL
->BufferSamplesSOFT
)
1159 This
->ExtAL
->BufferSamplesSOFT(buf
->buffers
[0],
1160 buf
->format
.Format
.nSamplesPerSec
, buf
->buf_format
,
1161 buf
->buf_size
/buf
->format
.Format
.nBlockAlign
,
1162 buf
->in_chans
, buf
->in_type
, buf
->data
);
1163 else if(This
->ExtAL
->BufferSubData
)
1164 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1165 buf
->data
, buf
->buf_size
,
1166 buf
->format
.Format
.nSamplesPerSec
);
1172 if(This
->primary
->nsources
)
1174 This
->source
= This
->primary
->sources
[--This
->primary
->nsources
];
1175 alSourcef(This
->source
, AL_GAIN
, 1.0f
);
1176 alSourcef(This
->source
, AL_PITCH
, 1.0f
);
1181 alGenSources(1, &This
->source
);
1182 if(alGetError() != AL_NO_ERROR
)
1186 ds3dbuffer
= &This
->ds3dbuffer
;
1187 ds3dbuffer
->dwSize
= sizeof(*ds3dbuffer
);
1188 ds3dbuffer
->vPosition
.x
= 0.0;
1189 ds3dbuffer
->vPosition
.y
= 0.0;
1190 ds3dbuffer
->vPosition
.z
= 0.0;
1191 ds3dbuffer
->vVelocity
.x
= 0.0;
1192 ds3dbuffer
->vVelocity
.y
= 0.0;
1193 ds3dbuffer
->vVelocity
.z
= 0.0;
1194 ds3dbuffer
->dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1195 ds3dbuffer
->dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1196 ds3dbuffer
->vConeOrientation
.x
= 0.0;
1197 ds3dbuffer
->vConeOrientation
.y
= 0.0;
1198 ds3dbuffer
->vConeOrientation
.z
= 1.0;
1199 ds3dbuffer
->lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1200 ds3dbuffer
->flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1201 ds3dbuffer
->flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1202 ds3dbuffer
->dwMode
= DS3DMODE_NORMAL
;
1204 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
1206 if(This
->primary
->auxslot
!= 0)
1208 alSource3i(This
->source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1212 hr
= IDirectSound3DBuffer_SetAllParameters(&This
->IDirectSound3DBuffer_iface
, ds3dbuffer
, DS3D_IMMEDIATE
);
1215 ERR("SetAllParameters failed\n");
1221 ALuint source
= This
->source
;
1223 if(This
->primary
->auxslot
!= 0)
1225 /* Simple hack to make reverb affect non-3D sounds too */
1226 alSource3i(source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1227 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1230 /* Non-3D sources aren't distance attenuated */
1231 This
->ds3dmode
= DS3DMODE_DISABLE
;
1232 alSource3f(source
, AL_POSITION
, 0.0f
, 1.0f
, 0.0f
);
1233 alSource3f(source
, AL_VELOCITY
, 0.0f
, 0.0f
, 0.0f
);
1234 alSource3f(source
, AL_DIRECTION
, 0.0f
, 0.0f
, 0.0f
);
1235 alSourcef(source
, AL_CONE_OUTER_GAIN
, 1.0f
);
1236 alSourcef(source
, AL_REFERENCE_DISTANCE
, 1.0f
);
1237 alSourcef(source
, AL_MAX_DISTANCE
, 1000.0f
);
1238 alSourcef(source
, AL_ROLLOFF_FACTOR
, 0.0f
);
1239 alSourcei(source
, AL_CONE_INNER_ANGLE
, 360);
1240 alSourcei(source
, AL_CONE_OUTER_ANGLE
, 360);
1241 alSourcei(source
, AL_SOURCE_RELATIVE
, AL_TRUE
);
1248 LeaveCriticalSection(This
->crst
);
1253 static HRESULT WINAPI
DS8Buffer_Lock(IDirectSoundBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1255 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1259 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1263 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1264 return DSERR_INVALIDPARAM
;
1267 EnterCriticalSection(This
->crst
);
1268 setALContext(This
->ctx
);
1272 if(ptr2
) *ptr2
= NULL
;
1275 hr
= DSERR_INVALIDPARAM
;
1276 if((flags
&DSBLOCK_FROMWRITECURSOR
))
1277 DS8Buffer_GetCurrentPosition(iface
, NULL
, &ofs
);
1278 else if(ofs
>= This
->buffer
->buf_size
)
1280 WARN("Invalid ofs %u\n", ofs
);
1283 if((flags
&DSBLOCK_ENTIREBUFFER
))
1284 bytes
= This
->buffer
->buf_size
;
1285 else if(bytes
> This
->buffer
->buf_size
)
1287 WARN("Invalid size %u\n", bytes
);
1291 *ptr1
= This
->buffer
->data
+ ofs
;
1292 if(ofs
+bytes
>= This
->buffer
->buf_size
)
1294 *len1
= This
->buffer
->buf_size
- ofs
;
1295 remain
= bytes
- *len1
;
1303 This
->buffer
->locked
= TRUE
;
1305 if(ptr2
&& len2
&& remain
)
1307 *ptr2
= This
->buffer
->data
;
1314 LeaveCriticalSection(This
->crst
);
1318 static HRESULT WINAPI
DS8Buffer_Play(IDirectSoundBuffer8
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1320 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1321 ALint type
, state
= AL_STOPPED
;
1325 TRACE("%p\n", This
);
1327 EnterCriticalSection(This
->crst
);
1328 setALContext(This
->ctx
);
1330 hr
= DSERR_BUFFERLOST
;
1331 if(This
->bufferlost
)
1333 WARN("Buffer %p lost\n", This
);
1337 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1339 if(!(This
->buffer
->dsbflags
&(DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCSOFTWARE
)))
1341 if(flags
& DSBPLAY_LOCSOFTWARE
)
1342 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1344 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1349 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This
->buffer
, prio
);
1350 hr
= DSERR_INVALIDPARAM
;
1354 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1355 if(This
->buffer
->numsegs
> 1)
1357 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1358 if(state
!= AL_PLAYING
&& This
->isplaying
)
1363 alGetSourcei(This
->source
, AL_SOURCE_TYPE
, &type
);
1364 alSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1369 if(state
== AL_PLAYING
)
1372 /* alSourceQueueBuffers will implicitly set type to streaming */
1373 if(This
->buffer
->numsegs
== 1)
1375 if(type
!= AL_STATIC
)
1376 alSourcei(This
->source
, AL_BUFFER
, This
->buffer
->buffers
[0]);
1377 alSourcePlay(This
->source
);
1379 if(alGetError() != AL_NO_ERROR
)
1381 ERR("Couldn't start source\n");
1382 This
->curidx
= (This
->buffer
->numsegs
-1+This
->curidx
)%This
->buffer
->numsegs
;
1383 alSourcei(This
->source
, AL_BUFFER
, 0);
1388 This
->isplaying
= TRUE
;
1392 DS8Buffer_addnotify(This
);
1393 DS8Buffer_starttimer(This
->primary
);
1395 else if(This
->buffer
->numsegs
> 1)
1396 DS8Buffer_starttimer(This
->primary
);
1400 LeaveCriticalSection(This
->crst
);
1404 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1406 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1408 TRACE("%p\n", This
);
1410 EnterCriticalSection(This
->crst
);
1411 setALContext(This
->ctx
);
1413 hr
= DSERR_INVALIDPARAM
;
1414 if(pos
>= This
->buffer
->buf_size
)
1417 if(This
->buffer
->numsegs
> 1)
1419 DS8Data
*buf
= This
->buffer
;
1420 This
->curidx
= pos
/buf
->segsize
;
1421 if(This
->curidx
>= buf
->numsegs
)
1422 This
->curidx
= buf
->numsegs
- 1;
1425 alSourceStop(This
->source
);
1426 alSourcei(This
->source
, AL_BUFFER
, 0);
1431 alSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1432 This
->lastpos
= pos
;
1437 LeaveCriticalSection(This
->crst
);
1441 static HRESULT WINAPI
DS8Buffer_SetFormat(IDirectSoundBuffer8
*iface
, const WAVEFORMATEX
*wfx
)
1443 /* This call only works on primary buffers */
1444 WARN("(%p)->(%p)\n", iface
, wfx
);
1445 return DSERR_INVALIDCALL
;
1448 static HRESULT WINAPI
DS8Buffer_SetVolume(IDirectSoundBuffer8
*iface
, LONG vol
)
1450 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1453 TRACE("(%p)->(%d)\n", iface
, vol
);
1455 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
1457 WARN("Invalid volume (%d)\n", vol
);
1458 return DSERR_INVALIDPARAM
;
1461 EnterCriticalSection(This
->crst
);
1462 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
1463 hr
= DSERR_CONTROLUNAVAIL
;
1466 ALfloat fvol
= mB_to_gain(vol
);
1467 setALContext(This
->ctx
);
1468 alSourcef(This
->source
, AL_GAIN
, fvol
);
1471 LeaveCriticalSection(This
->crst
);
1476 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1478 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1481 TRACE("(%p)->(%d)\n", iface
, pan
);
1483 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1485 WARN("invalid parameter: pan = %d\n", pan
);
1486 return DSERR_INVALIDPARAM
;
1489 EnterCriticalSection(This
->crst
);
1490 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1491 hr
= DSERR_CONTROLUNAVAIL
;
1495 pos
[0] = (pan
-DSBPAN_LEFT
) * 2.0 / (ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 1.0;
1496 /* NOTE: Strict movement along the X plane can cause the sound to jump
1497 * between left and right sharply. Using a curved path helps smooth it
1499 pos
[1] = sqrt(1.0 - pos
[0]*pos
[0]);
1502 setALContext(This
->ctx
);
1503 alSourcefv(This
->source
, AL_POSITION
, pos
);
1507 if(pan
!= 0 && This
->buffer
->format
.Format
.nChannels
> 1)
1508 FIXME("Panning for multi-channel buffers is not supported\n");
1510 LeaveCriticalSection(This
->crst
);
1515 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1517 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1520 TRACE("(%p)->(%u)\n", iface
, freq
);
1522 if(freq
< DSBFREQUENCY_MIN
|| freq
> DSBFREQUENCY_MAX
)
1524 WARN("invalid parameter: freq = %d\n", freq
);
1525 return DSERR_INVALIDPARAM
;
1528 EnterCriticalSection(This
->crst
);
1529 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1530 hr
= DSERR_CONTROLUNAVAIL
;
1533 ALfloat pitch
= 1.0f
;
1534 if(freq
!= DSBFREQUENCY_ORIGINAL
)
1535 pitch
= freq
/ (ALfloat
)This
->buffer
->format
.Format
.nSamplesPerSec
;
1537 setALContext(This
->ctx
);
1538 alSourcef(This
->source
, AL_PITCH
, pitch
);
1542 LeaveCriticalSection(This
->crst
);
1546 static HRESULT WINAPI
DS8Buffer_Stop(IDirectSoundBuffer8
*iface
)
1548 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1551 TRACE("(%p)->()\n", iface
);
1553 EnterCriticalSection(This
->crst
);
1554 setALContext(This
->ctx
);
1556 alSourcePause(This
->source
);
1558 /* Mac OS X doesn't immediately report state change
1559 * if Play() is immediately called after Stop, this can be fatal,
1560 * the buffer would never be restarted
1564 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1565 if(state
!= AL_PLAYING
)
1570 This
->isplaying
= FALSE
;
1573 LeaveCriticalSection(This
->crst
);
1578 static HRESULT WINAPI
DS8Buffer_Unlock(IDirectSoundBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1580 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1581 DS8Data
*buf
= This
->buffer
;
1582 DWORD bufsize
= buf
->buf_size
;
1583 DWORD_PTR ofs1
, ofs2
;
1584 DWORD_PTR boundary
= (DWORD_PTR
)buf
->data
;
1587 TRACE("(%p)->(%p, %u, %p, %u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1589 EnterCriticalSection(This
->crst
);
1590 setALContext(This
->ctx
);
1592 This
->buffer
->locked
= 0;
1593 hr
= DSERR_INVALIDPARAM
;
1595 /* Make sure offset is between boundary and boundary + bufsize */
1596 ofs1
= (DWORD_PTR
)ptr1
;
1597 ofs2
= (DWORD_PTR
)ptr2
;
1600 if(ofs2
&& ofs2
!= boundary
)
1604 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1613 if(This
->ExtAL
->BufferDataStatic
)
1616 if(This
->ExtAL
->BufferSubSamplesSOFT
)
1618 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1620 ptr1
= (BYTE
*)ptr1
- (ofs1
%format
->nBlockAlign
);
1621 ofs1
/= format
->nBlockAlign
;
1622 len1
/= format
->nBlockAlign
;
1624 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs1
, len1
,
1625 buf
->in_chans
, buf
->in_type
, ptr1
);
1626 ptr2
= (BYTE
*)ptr2
- (ofs2
%format
->nBlockAlign
);
1627 ofs2
/= format
->nBlockAlign
;
1628 len2
/= format
->nBlockAlign
;
1630 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs2
, len2
,
1631 buf
->in_chans
, buf
->in_type
, ptr2
);
1634 else if(This
->ExtAL
->BufferSubData
)
1636 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1638 len1
-= len1
%format
->nBlockAlign
;
1640 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr1
,
1642 len2
-= len2
%format
->nBlockAlign
;
1644 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr2
,
1650 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1651 buf
->data
, buf
->buf_size
,
1652 buf
->format
.Format
.nSamplesPerSec
);
1658 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1660 LeaveCriticalSection(This
->crst
);
1664 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1666 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1669 TRACE("(%p)->()\n", iface
);
1671 EnterCriticalSection(This
->crst
);
1672 if(This
->primary
->parent
->prio_level
< DSSCL_WRITEPRIMARY
||
1673 iface
== This
->primary
->write_emu
)
1675 This
->bufferlost
= 0;
1679 hr
= DSERR_BUFFERLOST
;
1680 LeaveCriticalSection(This
->crst
);
1685 static HRESULT WINAPI
DS8Buffer_SetFX(IDirectSoundBuffer8
*iface
, DWORD fxcount
, DSEFFECTDESC
*desc
, DWORD
*rescodes
)
1687 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1690 TRACE("(%p)->(%u, %p, %p)\n", This
, fxcount
, desc
, rescodes
);
1692 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFX
))
1694 WARN("FX control not set\n");
1695 return DSERR_CONTROLUNAVAIL
;
1700 if(desc
|| rescodes
)
1702 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1703 return DSERR_INVALIDPARAM
;
1706 /* No effects; we can handle that */
1710 if(!desc
|| !rescodes
)
1712 WARN("NULL desc and/or result pointer specified.\n");
1713 return DSERR_INVALIDPARAM
;
1716 /* We don't (currently) handle DSound effects */
1717 for(i
= 0;i
< fxcount
;++i
)
1719 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc
[i
].guidDSFXClass
));
1720 rescodes
[i
] = DSFXR_FAILED
;
1723 return DSERR_INVALIDPARAM
;
1726 static HRESULT WINAPI
DS8Buffer_AcquireResources(IDirectSoundBuffer8
*iface
, DWORD flags
, DWORD fxcount
, DWORD
*rescodes
)
1728 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1730 TRACE("(%p)->(%u, %u, %p)\n", This
, flags
, fxcount
, rescodes
);
1732 /* effects aren't supported at the moment.. */
1733 if(fxcount
!= 0 || rescodes
)
1735 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1736 return DSERR_INVALIDPARAM
;
1739 EnterCriticalSection(This
->crst
);
1740 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1742 This
->buffer
->dsbflags
&= ~(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
);
1743 if((flags
&DSBPLAY_LOCSOFTWARE
))
1744 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1746 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1748 LeaveCriticalSection(This
->crst
);
1753 static HRESULT WINAPI
DS8Buffer_GetObjectInPath(IDirectSoundBuffer8
*iface
, REFGUID guid
, DWORD idx
, REFGUID rguidiface
, void **ppv
)
1755 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface
, debugstr_guid(guid
), idx
, debugstr_guid(rguidiface
), ppv
);
1759 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
=
1761 DS8Buffer_QueryInterface
,
1765 DS8Buffer_GetCurrentPosition
,
1766 DS8Buffer_GetFormat
,
1767 DS8Buffer_GetVolume
,
1769 DS8Buffer_GetFrequency
,
1770 DS8Buffer_GetStatus
,
1771 DS8Buffer_Initialize
,
1774 DS8Buffer_SetCurrentPosition
,
1775 DS8Buffer_SetFormat
,
1776 DS8Buffer_SetVolume
,
1778 DS8Buffer_SetFrequency
,
1783 DS8Buffer_AcquireResources
,
1784 DS8Buffer_GetObjectInPath
1787 static inline DS8Buffer
*impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer
*iface
)
1789 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSound3DBuffer_iface
);
1792 static HRESULT WINAPI
DS8Buffer3D_QueryInterface(IDirectSound3DBuffer
*iface
, REFIID riid
, void **ppv
)
1794 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1795 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1798 static ULONG WINAPI
DS8Buffer3D_AddRef(IDirectSound3DBuffer
*iface
)
1800 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1803 InterlockedIncrement(&This
->all_ref
);
1804 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1805 TRACE("new refcount %d\n", ret
);
1810 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1812 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1815 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1816 TRACE("new refcount %d\n", ret
);
1817 if(InterlockedDecrement(&This
->all_ref
) == 0)
1818 DS8Buffer_Destroy(This
);
1823 static HRESULT WINAPI
DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer
*iface
, DS3DBUFFER
*ds3dbuffer
)
1825 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1829 TRACE("%p\n", This
);
1831 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
1833 WARN("Invalid parameters %p %u\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
1834 return DSERR_INVALIDPARAM
;
1836 ds3dbuf
.dwSize
= sizeof(ds3dbuf
);
1838 EnterCriticalSection(This
->crst
);
1839 setALContext(This
->ctx
);
1841 hr
= IDirectSound3DBuffer_GetPosition(iface
, &ds3dbuf
.vPosition
);
1843 hr
= IDirectSound3DBuffer_GetVelocity(iface
, &ds3dbuf
.vVelocity
);
1845 hr
= IDirectSound3DBuffer_GetConeAngles(iface
, &ds3dbuf
.dwInsideConeAngle
, &ds3dbuf
.dwOutsideConeAngle
);
1847 hr
= IDirectSound3DBuffer_GetConeOrientation(iface
, &ds3dbuf
.vConeOrientation
);
1849 hr
= IDirectSound3DBuffer_GetConeOutsideVolume(iface
, &ds3dbuf
.lConeOutsideVolume
);
1851 hr
= IDirectSound3DBuffer_GetMinDistance(iface
, &ds3dbuf
.flMinDistance
);
1853 hr
= IDirectSound3DBuffer_GetMaxDistance(iface
, &ds3dbuf
.flMaxDistance
);
1855 hr
= IDirectSound3DBuffer_GetMode(iface
, &ds3dbuf
.dwMode
);
1857 memcpy(ds3dbuffer
, &ds3dbuf
, sizeof(ds3dbuf
));
1860 LeaveCriticalSection(This
->crst
);
1865 static HRESULT WINAPI
DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer
*iface
, DWORD
*pdwInsideConeAngle
, DWORD
*pdwOutsideConeAngle
)
1867 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1868 ALint inangle
, outangle
;
1870 TRACE("(%p)->(%p, %p)\n", This
, pdwInsideConeAngle
, pdwOutsideConeAngle
);
1871 if(!pdwInsideConeAngle
|| !pdwOutsideConeAngle
)
1873 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle
, pdwOutsideConeAngle
);
1874 return DSERR_INVALIDPARAM
;
1877 EnterCriticalSection(This
->crst
);
1878 setALContext(This
->ctx
);
1880 alGetSourcei(This
->source
, AL_CONE_INNER_ANGLE
, &inangle
);
1881 alGetSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, &outangle
);
1883 *pdwInsideConeAngle
= inangle
;
1884 *pdwOutsideConeAngle
= outangle
;
1887 LeaveCriticalSection(This
->crst
);
1892 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1894 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1897 TRACE("(%p)->(%p)\n", This
, orient
);
1900 WARN("Invalid pointer\n");
1901 return DSERR_INVALIDPARAM
;
1904 EnterCriticalSection(This
->crst
);
1905 setALContext(This
->ctx
);
1907 alGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1911 orient
->z
= -dir
[2];
1914 LeaveCriticalSection(This
->crst
);
1919 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1921 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1924 TRACE("(%p)->(%p)\n", This
, vol
);
1927 WARN("Invalid pointer\n");
1928 return DSERR_INVALIDPARAM
;
1931 EnterCriticalSection(This
->crst
);
1932 setALContext(This
->ctx
);
1934 alGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1936 *vol
= gain_to_mB(gain
);
1937 *vol
= max(*vol
, DSBVOLUME_MIN
);
1938 *vol
= min(*vol
, DSBVOLUME_MAX
);
1941 LeaveCriticalSection(This
->crst
);
1945 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1947 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1950 TRACE("(%p)->(%p)\n", This
, maxdist
);
1953 WARN("Invalid pointer\n");
1954 return DSERR_INVALIDPARAM
;
1957 EnterCriticalSection(This
->crst
);
1958 setALContext(This
->ctx
);
1960 alGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
1965 LeaveCriticalSection(This
->crst
);
1970 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
1972 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1975 TRACE("(%p)->(%p)\n", This
, mindist
);
1978 WARN("Invalid pointer\n");
1979 return DSERR_INVALIDPARAM
;
1982 EnterCriticalSection(This
->crst
);
1983 setALContext(This
->ctx
);
1985 alGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
1990 LeaveCriticalSection(This
->crst
);
1995 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
1997 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1999 TRACE("(%p)->(%p)\n", This
, mode
);
2002 WARN("Invalid pointer\n");
2003 return DSERR_INVALIDPARAM
;
2006 EnterCriticalSection(This
->crst
);
2007 *mode
= This
->ds3dmode
;
2008 LeaveCriticalSection(This
->crst
);
2013 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
2015 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2018 TRACE("(%p)->(%p)\n", This
, pos
);
2021 WARN("Invalid pointer\n");
2022 return DSERR_INVALIDPARAM
;
2025 EnterCriticalSection(This
->crst
);
2026 setALContext(This
->ctx
);
2028 alGetSourcefv(This
->source
, AL_POSITION
, alpos
);
2035 LeaveCriticalSection(This
->crst
);
2040 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
2042 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2045 TRACE("(%p)->(%p)\n", This
, vel
);
2048 WARN("Invalid pointer\n");
2049 return DSERR_INVALIDPARAM
;
2052 EnterCriticalSection(This
->crst
);
2053 setALContext(This
->ctx
);
2055 alGetSourcefv(This
->source
, AL_VELOCITY
, alvel
);
2062 LeaveCriticalSection(This
->crst
);
2067 static HRESULT WINAPI
DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer
*iface
, const DS3DBUFFER
*ds3dbuffer
, DWORD apply
)
2069 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2070 TRACE("(%p)->(%p, %u)\n", This
, ds3dbuffer
, apply
);
2072 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
2074 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
2075 return DSERR_INVALIDPARAM
;
2078 if(ds3dbuffer
->dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2079 ds3dbuffer
->dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2081 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer
->dwInsideConeAngle
,
2082 ds3dbuffer
->dwOutsideConeAngle
);
2083 return DSERR_INVALIDPARAM
;
2086 if(ds3dbuffer
->lConeOutsideVolume
> DSBVOLUME_MAX
||
2087 ds3dbuffer
->lConeOutsideVolume
< DSBVOLUME_MIN
)
2089 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer
->lConeOutsideVolume
);
2090 return DSERR_INVALIDPARAM
;
2093 if(ds3dbuffer
->flMaxDistance
< 0.0f
)
2095 WARN("Invalid max distance (%f)\n", ds3dbuffer
->flMaxDistance
);
2096 return DSERR_INVALIDPARAM
;
2099 if(ds3dbuffer
->flMinDistance
< 0.0f
)
2101 WARN("Invalid min distance (%f)\n", ds3dbuffer
->flMinDistance
);
2102 return DSERR_INVALIDPARAM
;
2105 if(ds3dbuffer
->dwMode
!= DS3DMODE_NORMAL
&&
2106 ds3dbuffer
->dwMode
!= DS3DMODE_HEADRELATIVE
&&
2107 ds3dbuffer
->dwMode
!= DS3DMODE_DISABLE
)
2109 WARN("Invalid mode (%u)\n", ds3dbuffer
->dwMode
);
2110 return DSERR_INVALIDPARAM
;
2113 EnterCriticalSection(This
->crst
);
2114 setALContext(This
->ctx
);
2115 IDirectSound3DBuffer_SetPosition(iface
, ds3dbuffer
->vPosition
.x
, ds3dbuffer
->vPosition
.y
, ds3dbuffer
->vPosition
.z
, apply
);
2116 IDirectSound3DBuffer_SetVelocity(iface
, ds3dbuffer
->vVelocity
.x
, ds3dbuffer
->vVelocity
.y
, ds3dbuffer
->vVelocity
.z
, apply
);
2117 IDirectSound3DBuffer_SetConeAngles(iface
, ds3dbuffer
->dwInsideConeAngle
, ds3dbuffer
->dwOutsideConeAngle
, apply
);
2118 IDirectSound3DBuffer_SetConeOrientation(iface
, ds3dbuffer
->vConeOrientation
.x
, ds3dbuffer
->vConeOrientation
.y
, ds3dbuffer
->vConeOrientation
.z
, apply
);
2119 IDirectSound3DBuffer_SetConeOutsideVolume(iface
, ds3dbuffer
->lConeOutsideVolume
, apply
);
2120 IDirectSound3DBuffer_SetMinDistance(iface
, ds3dbuffer
->flMinDistance
, apply
);
2121 IDirectSound3DBuffer_SetMaxDistance(iface
, ds3dbuffer
->flMaxDistance
, apply
);
2122 IDirectSound3DBuffer_SetMode(iface
, ds3dbuffer
->dwMode
, apply
);
2124 LeaveCriticalSection(This
->crst
);
2129 static HRESULT WINAPI
DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer
*iface
, DWORD dwInsideConeAngle
, DWORD dwOutsideConeAngle
, DWORD apply
)
2131 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2133 TRACE("(%p)->(%u, %u, %u)\n", This
, dwInsideConeAngle
, dwOutsideConeAngle
, apply
);
2134 if(dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2135 dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2137 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle
, dwOutsideConeAngle
);
2138 return DSERR_INVALIDPARAM
;
2141 EnterCriticalSection(This
->crst
);
2142 if(apply
== DS3D_DEFERRED
)
2144 This
->ds3dbuffer
.dwInsideConeAngle
= dwInsideConeAngle
;
2145 This
->ds3dbuffer
.dwOutsideConeAngle
= dwOutsideConeAngle
;
2146 This
->dirty
.bit
.cone_angles
= 1;
2150 setALContext(This
->ctx
);
2151 alSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
2152 alSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
2156 LeaveCriticalSection(This
->crst
);
2161 static HRESULT WINAPI
DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2163 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2165 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2167 EnterCriticalSection(This
->crst
);
2168 if(apply
== DS3D_DEFERRED
)
2170 This
->ds3dbuffer
.vConeOrientation
.x
= x
;
2171 This
->ds3dbuffer
.vConeOrientation
.y
= y
;
2172 This
->ds3dbuffer
.vConeOrientation
.z
= z
;
2173 This
->dirty
.bit
.cone_orient
= 1;
2177 setALContext(This
->ctx
);
2178 alSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
2182 LeaveCriticalSection(This
->crst
);
2187 static HRESULT WINAPI
DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG vol
, DWORD apply
)
2189 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2191 TRACE("(%p)->(%u, %u)\n", This
, vol
, apply
);
2192 if(vol
< DSBVOLUME_MIN
|| vol
> DSBVOLUME_MAX
)
2194 WARN("Invalid volume (%u)\n", vol
);
2195 return DSERR_INVALIDPARAM
;
2198 EnterCriticalSection(This
->crst
);
2199 if(apply
== DS3D_DEFERRED
)
2201 This
->ds3dbuffer
.lConeOutsideVolume
= vol
;
2202 This
->dirty
.bit
.cone_outsidevolume
= 1;
2206 setALContext(This
->ctx
);
2207 alSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
2211 LeaveCriticalSection(This
->crst
);
2216 static HRESULT WINAPI
DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE maxdist
, DWORD apply
)
2218 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2220 TRACE("(%p)->(%f, %u)\n", This
, maxdist
, apply
);
2223 WARN("Invalid max distance (%f)\n", maxdist
);
2224 return DSERR_INVALIDPARAM
;
2227 EnterCriticalSection(This
->crst
);
2228 if(apply
== DS3D_DEFERRED
)
2230 This
->ds3dbuffer
.flMaxDistance
= maxdist
;
2231 This
->dirty
.bit
.max_distance
= 1;
2235 setALContext(This
->ctx
);
2236 alSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
2240 LeaveCriticalSection(This
->crst
);
2245 static HRESULT WINAPI
DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE mindist
, DWORD apply
)
2247 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2249 TRACE("(%p)->(%f, %u)\n", This
, mindist
, apply
);
2252 WARN("Invalid min distance (%f)\n", mindist
);
2253 return DSERR_INVALIDPARAM
;
2256 EnterCriticalSection(This
->crst
);
2257 if(apply
== DS3D_DEFERRED
)
2259 This
->ds3dbuffer
.flMinDistance
= mindist
;
2260 This
->dirty
.bit
.min_distance
= 1;
2264 setALContext(This
->ctx
);
2265 alSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
2269 LeaveCriticalSection(This
->crst
);
2274 static HRESULT WINAPI
DS8Buffer3D_SetMode(IDirectSound3DBuffer
*iface
, DWORD mode
, DWORD apply
)
2276 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2278 TRACE("(%p)->(%u, %u)\n", This
, mode
, apply
);
2279 if(mode
!= DS3DMODE_NORMAL
&& mode
!= DS3DMODE_HEADRELATIVE
&&
2280 mode
!= DS3DMODE_DISABLE
)
2282 WARN("Invalid mode (%u)\n", mode
);
2283 return DSERR_INVALIDPARAM
;
2286 EnterCriticalSection(This
->crst
);
2287 if(apply
== DS3D_DEFERRED
)
2289 This
->ds3dbuffer
.dwMode
= mode
;
2290 This
->dirty
.bit
.mode
= 1;
2294 setALContext(This
->ctx
);
2295 alSourcei(This
->source
, AL_SOURCE_RELATIVE
,
2296 (mode
!= DS3DMODE_NORMAL
) ? AL_TRUE
: AL_FALSE
);
2297 alSourcef(This
->source
, AL_ROLLOFF_FACTOR
,
2298 (mode
== DS3DMODE_DISABLE
) ? 0.0f
: This
->primary
->rollofffactor
);
2299 This
->ds3dmode
= mode
;
2303 LeaveCriticalSection(This
->crst
);
2308 static HRESULT WINAPI
DS8Buffer3D_SetPosition(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2310 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2312 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2314 EnterCriticalSection(This
->crst
);
2315 if(apply
== DS3D_DEFERRED
)
2317 This
->ds3dbuffer
.vPosition
.x
= x
;
2318 This
->ds3dbuffer
.vPosition
.y
= y
;
2319 This
->ds3dbuffer
.vPosition
.z
= z
;
2320 This
->dirty
.bit
.pos
= 1;
2324 setALContext(This
->ctx
);
2325 alSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
2329 LeaveCriticalSection(This
->crst
);
2334 static HRESULT WINAPI
DS8Buffer3D_SetVelocity(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2336 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2338 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2340 EnterCriticalSection(This
->crst
);
2341 if(apply
== DS3D_DEFERRED
)
2343 This
->ds3dbuffer
.vVelocity
.x
= x
;
2344 This
->ds3dbuffer
.vVelocity
.y
= y
;
2345 This
->ds3dbuffer
.vVelocity
.z
= z
;
2346 This
->dirty
.bit
.vel
= 1;
2350 setALContext(This
->ctx
);
2351 alSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
2355 LeaveCriticalSection(This
->crst
);
2360 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2362 DS8Buffer3D_QueryInterface
,
2364 DS8Buffer3D_Release
,
2365 DS8Buffer3D_GetAllParameters
,
2366 DS8Buffer3D_GetConeAngles
,
2367 DS8Buffer3D_GetConeOrientation
,
2368 DS8Buffer3D_GetConeOutsideVolume
,
2369 DS8Buffer3D_GetMaxDistance
,
2370 DS8Buffer3D_GetMinDistance
,
2371 DS8Buffer3D_GetMode
,
2372 DS8Buffer3D_GetPosition
,
2373 DS8Buffer3D_GetVelocity
,
2374 DS8Buffer3D_SetAllParameters
,
2375 DS8Buffer3D_SetConeAngles
,
2376 DS8Buffer3D_SetConeOrientation
,
2377 DS8Buffer3D_SetConeOutsideVolume
,
2378 DS8Buffer3D_SetMaxDistance
,
2379 DS8Buffer3D_SetMinDistance
,
2380 DS8Buffer3D_SetMode
,
2381 DS8Buffer3D_SetPosition
,
2382 DS8Buffer3D_SetVelocity
2385 static inline DS8Buffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
2387 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundNotify_iface
);
2390 static HRESULT WINAPI
DS8BufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
2392 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2393 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2396 static ULONG WINAPI
DS8BufferNot_AddRef(IDirectSoundNotify
*iface
)
2398 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2401 InterlockedIncrement(&This
->all_ref
);
2402 ret
= InterlockedIncrement(&This
->not_ref
);
2403 TRACE("new refcount %d\n", ret
);
2408 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2410 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2413 ret
= InterlockedDecrement(&This
->not_ref
);
2414 TRACE("new refcount %d\n", ret
);
2415 if(InterlockedDecrement(&This
->all_ref
) == 0)
2416 DS8Buffer_Destroy(This
);
2421 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2423 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2424 DSBPOSITIONNOTIFY
*nots
;
2428 EnterCriticalSection(This
->crst
);
2429 hr
= DSERR_INVALIDPARAM
;
2430 if(count
&& !notifications
)
2433 hr
= IDirectSoundBuffer8_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2437 hr
= DSERR_INVALIDCALL
;
2438 if((state
&DSBSTATUS_PLAYING
))
2443 HeapFree(GetProcessHeap(), 0, This
->notify
);
2452 hr
= DSERR_INVALIDPARAM
;
2453 for(i
= 0;i
< count
;++i
)
2455 if(notifications
[i
].dwOffset
>= This
->buffer
->buf_size
&&
2456 notifications
[i
].dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
2461 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2464 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2466 HeapFree(GetProcessHeap(), 0, This
->notify
);
2467 This
->notify
= nots
;
2468 This
->nnotify
= count
;
2474 LeaveCriticalSection(This
->crst
);
2478 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
=
2480 DS8BufferNot_QueryInterface
,
2481 DS8BufferNot_AddRef
,
2482 DS8BufferNot_Release
,
2483 DS8BufferNot_SetNotificationPositions
2486 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2487 handled through secondary buffers. */
2488 static inline DS8Buffer
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
2490 return CONTAINING_RECORD(iface
, DS8Buffer
, IKsPropertySet_iface
);
2493 static HRESULT WINAPI
DS8BufferProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
2495 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2496 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2499 static ULONG WINAPI
DS8BufferProp_AddRef(IKsPropertySet
*iface
)
2501 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2504 InterlockedIncrement(&This
->all_ref
);
2505 ret
= InterlockedIncrement(&This
->prop_ref
);
2506 TRACE("new refcount %d\n", ret
);
2511 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2513 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2516 ret
= InterlockedDecrement(&This
->prop_ref
);
2517 TRACE("new refcount %d\n", ret
);
2518 if(InterlockedDecrement(&This
->all_ref
) == 0)
2519 DS8Buffer_Destroy(This
);
2524 static HRESULT WINAPI
DS8BufferProp_Get(IKsPropertySet
*iface
,
2525 REFGUID guidPropSet
, ULONG dwPropID
,
2526 LPVOID pInstanceData
, ULONG cbInstanceData
,
2527 LPVOID pPropData
, ULONG cbPropData
,
2530 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2531 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2533 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface
, debugstr_guid(guidPropSet
),
2534 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
2541 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2547 /* Not a known buffer/source property. Pass it to the listener */
2548 hr
= IKsPropertySet_Get(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2549 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
,
2556 static HRESULT WINAPI
DS8BufferProp_Set(IKsPropertySet
*iface
,
2557 REFGUID guidPropSet
, ULONG dwPropID
,
2558 LPVOID pInstanceData
, ULONG cbInstanceData
,
2559 LPVOID pPropData
, ULONG cbPropData
)
2561 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2562 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2564 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface
, debugstr_guid(guidPropSet
),
2565 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
2568 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2574 /* Not a known buffer/source property. Pass it to the listener */
2575 hr
= IKsPropertySet_Set(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2576 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
,
2583 static HRESULT WINAPI
DS8BufferProp_QuerySupport(IKsPropertySet
*iface
,
2584 REFGUID guidPropSet
, ULONG dwPropID
,
2585 PULONG pTypeSupport
)
2587 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2588 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2590 TRACE("(%p)->(%s, %u, %p)\n", iface
, debugstr_guid(guidPropSet
), dwPropID
, pTypeSupport
);
2597 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2603 /* Not a known buffer/source property. Pass it to the listener */
2604 hr
= IKsPropertySet_QuerySupport(&This
->primary
->IKsPropertySet_iface
,
2605 guidPropSet
, dwPropID
, pTypeSupport
);
2611 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2613 DS8BufferProp_QueryInterface
,
2614 DS8BufferProp_AddRef
,
2615 DS8BufferProp_Release
,
2618 DS8BufferProp_QuerySupport