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
;
83 static void trigger_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
)
86 for(i
= 0;i
< buf
->nnotify
;++i
)
88 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
89 HANDLE event
= not->hEventNotify
;
90 DWORD ofs
= not->dwOffset
;
92 if(ofs
== (DWORD
)DSBPN_OFFSETSTOP
)
101 if(ofs
< curpos
|| ofs
>= lastpos
)
107 if(ofs
>= lastpos
&& ofs
< curpos
)
112 static void CALLBACK
DS8Buffer_timer(UINT timerID
, UINT msg
, DWORD_PTR dwUser
,
113 DWORD_PTR dw1
, DWORD_PTR dw2
)
119 PostThreadMessageA(dwUser
, WM_USER
, 0, 0);
122 static void DS8Buffer_starttimer(DS8Primary
*prim
)
124 DWORD triggertime
, res
= DS_TIME_RES
;
125 ALint refresh
= FAKE_REFRESH_COUNT
;
131 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
133 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
134 getALCError(prim
->parent
->device
);
136 triggertime
= 1000 / refresh
;
137 if(triggertime
< time
.wPeriodMin
)
138 triggertime
= time
.wPeriodMin
;
139 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime
, refresh
);
141 if (res
< time
.wPeriodMin
)
142 res
= time
.wPeriodMin
;
143 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
144 WARN("Could not set minimum resolution, don't expect sound\n");
146 prim
->timer_res
= res
;
147 prim
->timer_id
= timeSetEvent(triggertime
, res
, DS8Buffer_timer
, prim
->thread_id
, TIME_PERIODIC
|TIME_KILL_SYNCHRONOUS
);
150 /* Should be called with critsect held and context set.. */
151 static void DS8Buffer_addnotify(DS8Buffer
*buf
)
156 list
= buf
->primary
->notifies
;
157 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
161 ERR("Buffer %p already in notification list\n", buf
);
165 if(buf
->primary
->nnotifies
== buf
->primary
->sizenotifies
)
167 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (buf
->primary
->nnotifies
+ 1) * sizeof(*list
));
170 buf
->primary
->sizenotifies
++;
172 list
[buf
->primary
->nnotifies
++] = buf
;
173 buf
->primary
->notifies
= list
;
176 static void DS8Buffer_removenotify(DS8Buffer
*buf
)
179 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
181 if(buf
== buf
->primary
->notifies
[i
])
183 buf
->primary
->notifies
[i
] =
184 buf
->primary
->notifies
[--buf
->primary
->nnotifies
];
190 static const char *get_fmtstr_PCM(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
192 out
->Format
= *format
;
193 out
->Format
.cbSize
= 0;
195 if(format
->wBitsPerSample
== 8)
197 *in_type
= AL_UNSIGNED_BYTE
;
198 switch(format
->nChannels
)
200 case 1: *in_chans
= AL_MONO
;
201 return "AL_FORMAT_MONO8";
202 case 2: *in_chans
= AL_STEREO
;
203 return "AL_FORMAT_STEREO8";
204 case 4: *in_chans
= AL_QUAD
;
205 return "AL_FORMAT_QUAD8";
206 case 6: *in_chans
= AL_5POINT1
;
207 return "AL_FORMAT_51CHN8";
208 case 7: *in_chans
= AL_6POINT1
;
209 return "AL_FORMAT_61CHN8";
210 case 8: *in_chans
= AL_7POINT1
;
211 return "AL_FORMAT_71CHN8";
215 else if(format
->wBitsPerSample
== 16)
218 switch(format
->nChannels
)
220 case 1: *in_chans
= AL_MONO
;
221 return "AL_FORMAT_MONO16";
222 case 2: *in_chans
= AL_STEREO
;
223 return "AL_FORMAT_STEREO16";
224 case 4: *in_chans
= AL_QUAD
;
225 return "AL_FORMAT_QUAD16";
226 case 6: *in_chans
= AL_5POINT1
;
227 return "AL_FORMAT_51CHN16";
228 case 7: *in_chans
= AL_6POINT1
;
229 return "AL_FORMAT_61CHN16";
230 case 8: *in_chans
= AL_7POINT1
;
231 return "AL_FORMAT_71CHN16";
235 #if 0 /* Will cause incorrect byte offsets */
236 else if(format
->wBitsPerSample
== 24 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
239 switch(format
->nChannels
)
241 case 1: *in_chans
= AL_MONO
;
243 case 2: *in_chans
= AL_STEREO
;
244 return "AL_STEREO32F";
245 case 4: *in_chans
= AL_QUAD
;
247 case 6: *in_chans
= AL_5POINT1
;
248 return "AL_5POINT1_32F";
249 case 7: *in_chans
= AL_6POINT1
;
250 return "AL_6POINT1_32F";
251 case 8: *in_chans
= AL_7POINT1
;
252 return "AL_7POINT1_32F";
257 else if(format
->wBitsPerSample
== 32 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
260 switch(format
->nChannels
)
262 case 1: *in_chans
= AL_MONO
;
264 case 2: *in_chans
= AL_STEREO
;
265 return "AL_STEREO32F";
266 case 4: *in_chans
= AL_QUAD
;
268 case 6: *in_chans
= AL_5POINT1
;
269 return "AL_5POINT1_32F";
270 case 7: *in_chans
= AL_6POINT1
;
271 return "AL_6POINT1_32F";
272 case 8: *in_chans
= AL_7POINT1
;
273 return "AL_7POINT1_32F";
278 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
279 format
->wBitsPerSample
, format
->nChannels
);
283 static const char *get_fmtstr_FLOAT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
285 out
->Format
= *format
;
286 out
->Format
.cbSize
= 0;
288 if(format
->wBitsPerSample
== 32 &&
289 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
292 switch(format
->nChannels
)
294 case 1: *in_chans
= AL_MONO
;
295 return "AL_FORMAT_MONO_FLOAT32";
296 case 2: *in_chans
= AL_STEREO
;
297 return "AL_FORMAT_STEREO_FLOAT32";
298 case 4: *in_chans
= AL_QUAD
;
299 return "AL_FORMAT_QUAD32";
300 case 6: *in_chans
= AL_5POINT1
;
301 return "AL_FORMAT_51CHN32";
302 case 7: *in_chans
= AL_6POINT1
;
303 return "AL_FORMAT_61CHN32";
304 case 8: *in_chans
= AL_7POINT1
;
305 return "AL_FORMAT_71CHN32";
309 #if 0 /* Will cause incorrect byte offsets */
310 else if(format
->wBitsPerSample
== 64 && prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
312 *in_type
= AL_DOUBLE
;
313 switch(format
->nChannels
)
315 case 1: *in_chans
= AL_MONO
;
317 case 2: *in_chans
= AL_STEREO
;
318 return "AL_STEREO32F";
319 case 4: *in_chans
= AL_QUAD
;
321 case 6: *in_chans
= AL_5POINT1
;
322 return "AL_5POINT1_32F";
323 case 7: *in_chans
= AL_6POINT1
;
324 return "AL_6POINT1_32F";
325 case 8: *in_chans
= AL_7POINT1
;
326 return "AL_7POINT1_32F";
332 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
333 format
->wBitsPerSample
, format
->nChannels
);
337 /* Speaker configs */
338 #define MONO SPEAKER_FRONT_CENTER
339 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
340 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
341 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
342 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
343 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
344 #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)
346 static const char *get_fmtstr_EXT(const DS8Primary
*prim
, const WAVEFORMATEX
*format
, WAVEFORMATEXTENSIBLE
*out
, ALenum
*in_chans
, ALenum
*in_type
)
348 *out
= *(const WAVEFORMATEXTENSIBLE
*)format
;
349 out
->Format
.cbSize
= sizeof(*out
) - sizeof(out
->Format
);
351 if(!out
->Samples
.wValidBitsPerSample
)
352 out
->Samples
.wValidBitsPerSample
= out
->Format
.wBitsPerSample
;
353 else if(out
->Samples
.wValidBitsPerSample
!= out
->Format
.wBitsPerSample
)
355 FIXME("Padded samples not supported (%u of %u)\n", out
->Samples
.wValidBitsPerSample
, out
->Format
.wBitsPerSample
);
359 if(out
->dwChannelMask
!= MONO
&& out
->dwChannelMask
!= STEREO
&&
360 !prim
->SupportedExt
[EXT_MCFORMATS
] && !prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
362 WARN("Multi-channel not available\n");
366 if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
368 if(out
->Samples
.wValidBitsPerSample
== 8)
370 *in_type
= AL_UNSIGNED_BYTE
;
371 switch(out
->dwChannelMask
)
373 case MONO
: *in_chans
= AL_MONO
;
374 return "AL_FORMAT_MONO8";
375 case STEREO
: *in_chans
= AL_STEREO
;
376 return "AL_FORMAT_STEREO8";
377 case REAR
: *in_chans
= AL_REAR
;
378 return "AL_FORMAT_REAR8";
379 case QUAD
: *in_chans
= AL_QUAD
;
380 return "AL_FORMAT_QUAD8";
381 case X5DOT1
: *in_chans
= AL_5POINT1
;
382 return "AL_FORMAT_51CHN8";
383 case X6DOT1
: *in_chans
= AL_6POINT1
;
384 return "AL_FORMAT_61CHN8";
385 case X7DOT1
: *in_chans
= AL_7POINT1
;
386 return "AL_FORMAT_71CHN8";
390 else if(out
->Samples
.wValidBitsPerSample
== 16)
393 switch(out
->dwChannelMask
)
395 case MONO
: *in_chans
= AL_MONO
;
396 return "AL_FORMAT_MONO16";
397 case STEREO
: *in_chans
= AL_STEREO
;
398 return "AL_FORMAT_STEREO16";
399 case REAR
: *in_chans
= AL_REAR
;
400 return "AL_FORMAT_REAR16";
401 case QUAD
: *in_chans
= AL_QUAD
;
402 return "AL_FORMAT_QUAD16";
403 case X5DOT1
: *in_chans
= AL_5POINT1
;
404 return "AL_FORMAT_51CHN16";
405 case X6DOT1
: *in_chans
= AL_6POINT1
;
406 return "AL_FORMAT_61CHN16";
407 case X7DOT1
: *in_chans
= AL_7POINT1
;
408 return "AL_FORMAT_71CHN16";
413 else if(out
->Samples
.wValidBitsPerSample
== 24 &&
414 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
417 switch(out
->dwChannelMask
)
419 case MONO
: *in_chans
= AL_MONO
;
421 case STEREO
: *in_chans
= AL_STEREO
;
422 return "AL_STEREO32F";
423 case REAR
: *in_chans
= AL_REAR
;
425 case QUAD
: *in_chans
= AL_QUAD
;
427 case X5DOT1
: *in_chans
= AL_5POINT1
;
428 return "AL_5POINT1_32F";
429 case X6DOT1
: *in_chans
= AL_6POINT1
;
430 return "AL_6POINT1_32F";
431 case X7DOT1
: *in_chans
= AL_7POINT1
;
432 return "AL_7POINT1_32F";
437 else if(out
->Samples
.wValidBitsPerSample
== 32 &&
438 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
441 switch(out
->dwChannelMask
)
443 case MONO
: *in_chans
= AL_MONO
;
445 case STEREO
: *in_chans
= AL_STEREO
;
446 return "AL_STEREO32F";
447 case REAR
: *in_chans
= AL_REAR
;
449 case QUAD
: *in_chans
= AL_QUAD
;
451 case X5DOT1
: *in_chans
= AL_5POINT1
;
452 return "AL_5POINT1_32F";
453 case X6DOT1
: *in_chans
= AL_6POINT1
;
454 return "AL_6POINT1_32F";
455 case X7DOT1
: *in_chans
= AL_7POINT1
;
456 return "AL_7POINT1_32F";
461 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
462 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
465 else if(IsEqualGUID(&out
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
466 (prim
->SupportedExt
[EXT_FLOAT32
] || prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
]))
468 if(out
->Samples
.wValidBitsPerSample
== 32)
471 switch(out
->dwChannelMask
)
473 case MONO
: *in_chans
= AL_MONO
;
474 return "AL_FORMAT_MONO_FLOAT32";
475 case STEREO
: *in_chans
= AL_STEREO
;
476 return "AL_FORMAT_STEREO_FLOAT32";
477 case REAR
: *in_chans
= AL_REAR
;
478 return "AL_FORMAT_REAR32";
479 case QUAD
: *in_chans
= AL_QUAD
;
480 return "AL_FORMAT_QUAD32";
481 case X5DOT1
: *in_chans
= AL_5POINT1
;
482 return "AL_FORMAT_51CHN32";
483 case X6DOT1
: *in_chans
= AL_6POINT1
;
484 return "AL_FORMAT_61CHN32";
485 case X7DOT1
: *in_chans
= AL_7POINT1
;
486 return "AL_FORMAT_71CHN32";
491 else if(out
->Samples
.wValidBitsPerSample
== 64 &&
492 prim
->SupportedExt
[SOFT_BUFFER_SAMPLES
])
494 *in_type
= AL_DOUBLE
;
495 switch(out
->dwChannelMask
)
497 case MONO
: *in_chans
= AL_MONO
;
499 case STEREO
: *in_chans
= AL_STEREO
;
500 return "AL_STEREO32F";
501 case REAR
: *in_chans
= AL_REAR
;
503 case QUAD
: *in_chans
= AL_QUAD
;
505 case X5DOT1
: *in_chans
= AL_5POINT1
;
506 return "AL_5POINT1_32F";
507 case X6DOT1
: *in_chans
= AL_6POINT1
;
508 return "AL_6POINT1_32F";
509 case X7DOT1
: *in_chans
= AL_7POINT1
;
510 return "AL_7POINT1_32F";
517 WARN("Invalid float bits: %u\n", out
->Samples
.wValidBitsPerSample
);
521 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
522 out
->Samples
.wValidBitsPerSample
, out
->dwChannelMask
);
525 else if(!IsEqualGUID(&out
->SubFormat
, &GUID_NULL
))
526 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out
->SubFormat
));
530 static void DS8Data_Release(DS8Data
*This
);
531 static HRESULT
DS8Data_Create(DS8Data
**ppv
, const DSBUFFERDESC
*desc
, DS8Primary
*prim
)
533 HRESULT hr
= DSERR_INVALIDPARAM
;
534 const WAVEFORMATEX
*format
;
535 const char *fmt_str
= NULL
;
538 format
= desc
->lpwfxFormat
;
539 TRACE("Requested buffer format:\n"
540 " FormatTag = 0x%04x\n"
542 " SamplesPerSec = %u\n"
543 " AvgBytesPerSec = %u\n"
545 " BitsPerSample = %d\n",
546 format
->wFormatTag
, format
->nChannels
,
547 format
->nSamplesPerSec
, format
->nAvgBytesPerSec
,
548 format
->nBlockAlign
, format
->wBitsPerSample
);
550 if(format
->nBlockAlign
== 0)
552 WARN("Invalid BlockAlign specified\n");
553 return DSERR_INVALIDPARAM
;
556 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
557 * will need the EAX-RAM extension. Currently, we just tell the app it
558 * gets what it wanted. */
559 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
561 return E_OUTOFMEMORY
;
564 pBuffer
->dsbflags
= desc
->dwFlags
;
565 if((pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
)) == (DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
))
567 WARN("Hardware and software location requested\n");
570 if(!(pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCDEFER
)))
571 pBuffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
573 pBuffer
->buf_size
= desc
->dwBufferBytes
+ format
->nBlockAlign
- 1;
574 pBuffer
->buf_size
-= pBuffer
->buf_size
%format
->nBlockAlign
;
576 hr
= DSERR_BUFFERTOOSMALL
;
577 if(pBuffer
->buf_size
< DSBSIZE_MIN
)
580 hr
= DSERR_INVALIDPARAM
;
581 if(pBuffer
->buf_size
> DSBSIZE_MAX
)
584 pBuffer
->numsegs
= 1;
585 pBuffer
->segsize
= pBuffer
->buf_size
;
586 pBuffer
->lastsegsize
= pBuffer
->buf_size
;
588 if(!(pBuffer
->dsbflags
&DSBCAPS_STATIC
) && !prim
->ExtAL
.BufferSubData
&&
589 !prim
->ExtAL
.BufferSamplesSOFT
&& !prim
->ExtAL
.BufferDataStatic
)
591 ALCint refresh
= FAKE_REFRESH_COUNT
;
594 alcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
595 getALCError(prim
->parent
->device
);
597 newSize
= format
->nAvgBytesPerSec
/refresh
+ format
->nBlockAlign
- 1;
598 newSize
-= newSize
%format
->nBlockAlign
;
600 /* Make sure enough buffers are available */
601 if(newSize
> pBuffer
->buf_size
/(QBUFFERS
+2))
602 ERR("Buffer segments too large to stream (%u for %u)!\n",
603 newSize
, pBuffer
->buf_size
);
606 pBuffer
->numsegs
= pBuffer
->buf_size
/newSize
;
607 pBuffer
->segsize
= newSize
;
608 pBuffer
->lastsegsize
= pBuffer
->buf_size
- (newSize
*(pBuffer
->numsegs
-1));
609 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
610 pBuffer
->numsegs
, pBuffer
->segsize
, pBuffer
->lastsegsize
);
614 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
615 fmt_str
= get_fmtstr_PCM(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
616 else if(format
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
617 fmt_str
= get_fmtstr_FLOAT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
618 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
620 const WAVEFORMATEXTENSIBLE
*wfe
;
622 hr
= DSERR_CONTROLUNAVAIL
;
623 if(format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
624 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
627 wfe
= (const WAVEFORMATEXTENSIBLE
*)format
;
628 TRACE("Extensible values:\n"
630 " ChannelMask = %#x\n"
632 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
633 debugstr_guid(&wfe
->SubFormat
));
635 hr
= DSERR_INVALIDCALL
;
636 fmt_str
= get_fmtstr_EXT(prim
, format
, &pBuffer
->format
, &pBuffer
->in_chans
, &pBuffer
->in_type
);
639 ERR("Unhandled formattag 0x%04x\n", format
->wFormatTag
);
644 pBuffer
->buf_format
= alGetEnumValue(fmt_str
);
645 if(alGetError() != AL_NO_ERROR
|| pBuffer
->buf_format
== 0 ||
646 pBuffer
->buf_format
== -1)
648 WARN("Could not get OpenAL format from %s\n", fmt_str
);
653 pBuffer
->buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
->buffers
)*pBuffer
->numsegs
);
654 pBuffer
->data
= HeapAlloc(GetProcessHeap(), 0, pBuffer
->buf_size
);
655 if(!pBuffer
->buffers
|| !pBuffer
->data
)
658 alGenBuffers(pBuffer
->numsegs
, pBuffer
->buffers
);
665 DS8Data_Release(pBuffer
);
669 static void DS8Data_AddRef(DS8Data
*data
)
671 InterlockedIncrement(&data
->ref
);
674 /* This function is always called with the device lock held */
675 static void DS8Data_Release(DS8Data
*This
)
677 if(InterlockedDecrement(&This
->ref
)) return;
679 TRACE("Deleting %p\n", This
);
680 if (This
->buffers
&& This
->buffers
[0])
682 alDeleteBuffers(This
->numsegs
, This
->buffers
);
685 HeapFree(GetProcessHeap(), 0, This
->buffers
);
686 HeapFree(GetProcessHeap(), 0, This
->data
);
687 HeapFree(GetProcessHeap(), 0, This
);
690 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*parent
, DS8Buffer
*orig
)
692 HRESULT hr
= DSERR_OUTOFMEMORY
;
697 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
700 This
->IDirectSoundBuffer8_iface
.lpVtbl
= (IDirectSoundBuffer8Vtbl
*)&DS8Buffer_Vtbl
;
701 This
->IDirectSound3DBuffer_iface
.lpVtbl
= (IDirectSound3DBufferVtbl
*)&DS8Buffer3d_Vtbl
;
702 This
->IDirectSoundNotify_iface
.lpVtbl
= (IDirectSoundNotifyVtbl
*)&DS8BufferNot_Vtbl
;
703 This
->IKsPropertySet_iface
.lpVtbl
= (IKsPropertySetVtbl
*)&DS8BufferProp_Vtbl
;
705 This
->primary
= parent
;
706 This
->ctx
= parent
->ctx
;
707 This
->ExtAL
= &parent
->ExtAL
;
708 This
->crst
= &parent
->crst
;
709 This
->ref
= This
->all_ref
= 1;
713 This
->buffer
= orig
->buffer
;
714 DS8Data_AddRef(This
->buffer
);
717 /* Append to buffer list */
718 bufs
= parent
->buffers
;
719 if(parent
->nbuffers
== parent
->sizebuffers
)
721 bufs
= HeapReAlloc(GetProcessHeap(), 0, bufs
, sizeof(*bufs
)*(1+parent
->nbuffers
));
723 parent
->sizebuffers
++;
725 parent
->buffers
= bufs
;
726 bufs
[parent
->nbuffers
++] = This
;
728 /* Disable until initialized.. */
729 This
->ds3dmode
= DS3DMODE_DISABLE
;
735 DS8Buffer_Destroy(This
);
739 void DS8Buffer_Destroy(DS8Buffer
*This
)
742 TRACE("Destroying %p\n", This
);
744 DS8Buffer_removenotify(This
);
746 /* Remove from list, if in list */
747 for(idx
= 0;idx
< This
->primary
->nbuffers
;++idx
)
749 if(This
->primary
->buffers
[idx
] == This
)
751 This
->primary
->buffers
[idx
] = This
->primary
->buffers
[This
->primary
->nbuffers
-1];
752 This
->primary
->nbuffers
--;
756 setALContext(This
->ctx
);
761 alSourceStop(This
->source
);
762 alSourcei(This
->source
, AL_BUFFER
, 0);
765 sources
= This
->primary
->sources
;
766 if(This
->primary
->nsources
== This
->primary
->sizesources
)
768 sources
= HeapReAlloc(GetProcessHeap(), 0, sources
, sizeof(*sources
)*(1+This
->primary
->nsources
));
770 alDeleteSources(1, &This
->source
);
772 This
->primary
->sizesources
++;
776 sources
[This
->primary
->nsources
++] = This
->source
;
777 This
->primary
->sources
= sources
;
780 HeapFree(GetProcessHeap(), 0, This
->notify
);
783 DS8Data_Release(This
->buffer
);
785 HeapFree(GetProcessHeap(), 0, This
);
788 static inline DS8Buffer
*impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8
*iface
)
790 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundBuffer8_iface
);
793 static HRESULT WINAPI
DS8Buffer_QueryInterface(IDirectSoundBuffer8
*iface
, REFIID riid
, void **ppv
)
795 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
797 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
800 if(IsEqualIID(riid
, &IID_IUnknown
) ||
801 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
802 *ppv
= &This
->IDirectSoundBuffer8_iface
;
803 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer8
))
805 if(This
->primary
->parent
->is_8
)
806 *ppv
= &This
->IDirectSoundBuffer8_iface
;
808 else if(IsEqualIID(riid
, &IID_IDirectSound3DBuffer
))
810 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
811 *ppv
= &This
->IDirectSound3DBuffer_iface
;
813 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
815 if((This
->buffer
->dsbflags
&DSBCAPS_CTRLPOSITIONNOTIFY
))
816 *ppv
= &This
->IDirectSoundNotify_iface
;
818 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
819 *ppv
= &This
->IKsPropertySet_iface
;
821 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
825 IUnknown_AddRef((IUnknown
*)*ppv
);
829 return E_NOINTERFACE
;
832 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
834 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
837 InterlockedIncrement(&This
->all_ref
);
838 ret
= InterlockedIncrement(&This
->ref
);
839 TRACE("new refcount %d\n", ret
);
844 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
846 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
849 ret
= InterlockedDecrement(&This
->ref
);
850 TRACE("new refcount %d\n", ret
);
851 if(InterlockedDecrement(&This
->all_ref
) == 0)
852 DS8Buffer_Destroy(This
);
857 static HRESULT WINAPI
DS8Buffer_GetCaps(IDirectSoundBuffer8
*iface
, DSBCAPS
*caps
)
859 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
861 TRACE("(%p)->(%p)\n", iface
, caps
);
863 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
865 WARN("Invalid DSBCAPS (%p, %u)\n", caps
, (caps
? caps
->dwSize
: 0));
866 return DSERR_INVALIDPARAM
;
869 caps
->dwFlags
= This
->buffer
->dsbflags
;
870 caps
->dwBufferBytes
= This
->buffer
->buf_size
;
871 caps
->dwUnlockTransferRate
= 4096;
872 caps
->dwPlayCpuOverhead
= 0;
876 static HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
878 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
879 WAVEFORMATEX
*format
= &This
->buffer
->format
.Format
;
880 UINT writecursor
, pos
;
882 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
884 EnterCriticalSection(This
->crst
);
885 setALContext(This
->ctx
);
887 if(This
->buffer
->numsegs
> 1)
889 ALint queued
= QBUFFERS
;
890 alGetSourcei(This
->source
, AL_BUFFERS_QUEUED
, &queued
);
893 pos
= (This
->curidx
+This
->buffer
->numsegs
-queued
)%This
->buffer
->numsegs
;
894 pos
*= This
->buffer
->segsize
;
895 writecursor
= This
->curidx
* This
->buffer
->segsize
;
897 else if(This
->ExtAL
->BufferSubData
|| This
->ExtAL
->BufferSamplesSOFT
)
899 ALint rwpos
[2] = { 0, 0 };
901 alGetSourceiv(This
->source
, AL_BYTE_RW_OFFSETS_SOFT
, rwpos
);
905 writecursor
= rwpos
[1];
912 alGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
913 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
917 if(status
== AL_PLAYING
)
919 writecursor
= format
->nSamplesPerSec
/ 100;
920 writecursor
*= format
->nBlockAlign
;
924 writecursor
= (writecursor
+ pos
) % This
->buffer
->buf_size
;
926 TRACE("%p Play pos = %u, write pos = %u\n", This
, pos
, writecursor
);
927 if(pos
>= This
->buffer
->buf_size
)
929 ERR("playpos >= buf_size\n");
930 pos
%= This
->buffer
->buf_size
;
932 if(writecursor
>= This
->buffer
->buf_size
)
934 ERR("writepos >= buf_size\n");
935 writecursor
%= This
->buffer
->buf_size
;
938 if(playpos
) *playpos
= pos
;
939 if(curpos
) *curpos
= writecursor
;
942 LeaveCriticalSection(This
->crst
);
947 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
949 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
953 TRACE("(%p)->(%p, %u, %p)\n", iface
, wfx
, allocated
, written
);
957 WARN("Cannot report format or format size\n");
958 return DSERR_INVALIDPARAM
;
961 EnterCriticalSection(This
->crst
);
962 size
= sizeof(This
->buffer
->format
.Format
) + This
->buffer
->format
.Format
.cbSize
;
966 hr
= DSERR_INVALIDPARAM
;
968 memcpy(wfx
, &This
->buffer
->format
.Format
, size
);
972 LeaveCriticalSection(This
->crst
);
977 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
979 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
982 TRACE("(%p)->(%p)\n", iface
, vol
);
986 WARN("Invalid pointer\n");
987 return DSERR_INVALIDPARAM
;
990 EnterCriticalSection(This
->crst
);
992 hr
= DSERR_CONTROLUNAVAIL
;
993 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
994 WARN("Volume control not set\n");
999 setALContext(This
->ctx
);
1000 alGetSourcef(This
->source
, AL_GAIN
, &gain
);
1004 *vol
= gain_to_mB(gain
);
1005 *vol
= min(*vol
, DSBVOLUME_MAX
);
1006 *vol
= max(*vol
, DSBVOLUME_MIN
);
1011 LeaveCriticalSection(This
->crst
);
1015 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
1017 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1020 TRACE("(%p)->(%p)\n", iface
, pan
);
1024 WARN("Invalid pointer\n");
1025 return DSERR_INVALIDPARAM
;
1028 EnterCriticalSection(This
->crst
);
1030 hr
= DSERR_CONTROLUNAVAIL
;
1031 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1032 WARN("Panning control not set\n");
1037 setALContext(This
->ctx
);
1038 alGetSourcefv(This
->source
, AL_POSITION
, pos
);
1042 *pan
= (LONG
)((pos
[0]+1.0) * (DSBPAN_RIGHT
-DSBPAN_LEFT
) / 2.0 + 0.5) + DSBPAN_LEFT
;
1043 *pan
= min(*pan
, DSBPAN_RIGHT
);
1044 *pan
= max(*pan
, DSBPAN_LEFT
);
1049 LeaveCriticalSection(This
->crst
);
1053 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
1055 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1058 TRACE("(%p)->(%p)\n", iface
, freq
);
1062 WARN("Invalid pointer\n");
1063 return DSERR_INVALIDPARAM
;
1066 EnterCriticalSection(This
->crst
);
1068 hr
= DSERR_CONTROLUNAVAIL
;
1069 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1070 WARN("Frequency control not set\n");
1073 ALfloat pitch
= 1.0f
;
1075 setALContext(This
->ctx
);
1076 alGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
1080 *freq
= (DWORD
)(This
->buffer
->format
.Format
.nSamplesPerSec
* pitch
);
1085 LeaveCriticalSection(This
->crst
);
1089 static HRESULT WINAPI
DS8Buffer_GetStatus(IDirectSoundBuffer8
*iface
, DWORD
*status
)
1091 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1092 ALint state
, looping
;
1094 TRACE("(%p)->(%p)\n", iface
, status
);
1098 WARN("Invalid pointer\n");
1099 return DSERR_INVALIDPARAM
;
1102 EnterCriticalSection(This
->crst
);
1104 setALContext(This
->ctx
);
1105 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1106 looping
= This
->islooping
;
1107 if(This
->buffer
->numsegs
== 1)
1108 alGetSourcei(This
->source
, AL_LOOPING
, &looping
);
1109 else if(state
!= AL_PLAYING
)
1110 state
= This
->isplaying
? AL_PLAYING
: AL_PAUSED
;
1115 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1117 if((This
->buffer
->dsbflags
&DSBCAPS_LOCSOFTWARE
))
1118 *status
|= DSBSTATUS_LOCSOFTWARE
;
1119 else if((This
->buffer
->dsbflags
&DSBCAPS_LOCHARDWARE
))
1120 *status
|= DSBSTATUS_LOCHARDWARE
;
1122 if(state
== AL_PLAYING
)
1123 *status
|= DSBSTATUS_PLAYING
| (looping
? DSBSTATUS_LOOPING
: 0);
1125 LeaveCriticalSection(This
->crst
);
1130 static HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
1132 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1133 DS3DBUFFER
*ds3dbuffer
;
1136 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
1138 EnterCriticalSection(This
->crst
);
1139 setALContext(This
->ctx
);
1141 hr
= DSERR_ALREADYINITIALIZED
;
1147 hr
= DSERR_INVALIDPARAM
;
1150 WARN("Missing DSound buffer description\n");
1153 if(!desc
->lpwfxFormat
)
1155 WARN("Missing buffer format (%p)\n", This
);
1158 if((desc
->dwFlags
&DSBCAPS_CTRL3D
) && desc
->lpwfxFormat
->nChannels
!= 1)
1160 if(This
->primary
->parent
->is_8
)
1162 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1164 WARN("Can't create multi-channel 3D buffers\n");
1167 ERR("Multi-channel 3D sounds are not spatialized\n");
1170 hr
= DS8Data_Create(&This
->buffer
, desc
, This
->primary
);
1175 DS8Data
*buf
= This
->buffer
;
1177 if(buf
->in_type
== AL_UNSIGNED_BYTE
)
1178 memset(buf
->data
, 0x80, buf
->buf_size
);
1180 memset(buf
->data
, 0x00, buf
->buf_size
);
1182 if(This
->ExtAL
->BufferDataStatic
)
1183 This
->ExtAL
->BufferDataStatic(buf
->buffers
[0], buf
->buf_format
,
1184 buf
->data
, buf
->buf_size
,
1185 buf
->format
.Format
.nSamplesPerSec
);
1186 else if(This
->ExtAL
->BufferSamplesSOFT
)
1187 This
->ExtAL
->BufferSamplesSOFT(buf
->buffers
[0],
1188 buf
->format
.Format
.nSamplesPerSec
, buf
->buf_format
,
1189 buf
->buf_size
/buf
->format
.Format
.nBlockAlign
,
1190 buf
->in_chans
, buf
->in_type
, buf
->data
);
1191 else if(This
->ExtAL
->BufferSubData
)
1192 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1193 buf
->data
, buf
->buf_size
,
1194 buf
->format
.Format
.nSamplesPerSec
);
1200 if(This
->primary
->nsources
)
1202 This
->source
= This
->primary
->sources
[--This
->primary
->nsources
];
1203 alSourcef(This
->source
, AL_GAIN
, 1.0f
);
1204 alSourcef(This
->source
, AL_PITCH
, 1.0f
);
1209 alGenSources(1, &This
->source
);
1210 if(alGetError() != AL_NO_ERROR
)
1214 ds3dbuffer
= &This
->ds3dbuffer
;
1215 ds3dbuffer
->dwSize
= sizeof(*ds3dbuffer
);
1216 ds3dbuffer
->vPosition
.x
= 0.0;
1217 ds3dbuffer
->vPosition
.y
= 0.0;
1218 ds3dbuffer
->vPosition
.z
= 0.0;
1219 ds3dbuffer
->vVelocity
.x
= 0.0;
1220 ds3dbuffer
->vVelocity
.y
= 0.0;
1221 ds3dbuffer
->vVelocity
.z
= 0.0;
1222 ds3dbuffer
->dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1223 ds3dbuffer
->dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1224 ds3dbuffer
->vConeOrientation
.x
= 0.0;
1225 ds3dbuffer
->vConeOrientation
.y
= 0.0;
1226 ds3dbuffer
->vConeOrientation
.z
= 1.0;
1227 ds3dbuffer
->lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1228 ds3dbuffer
->flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1229 ds3dbuffer
->flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1230 ds3dbuffer
->dwMode
= DS3DMODE_NORMAL
;
1232 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
1234 if(This
->primary
->auxslot
!= 0)
1236 alSource3i(This
->source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1240 hr
= IDirectSound3DBuffer_SetAllParameters(&This
->IDirectSound3DBuffer_iface
, ds3dbuffer
, DS3D_IMMEDIATE
);
1243 ERR("SetAllParameters failed\n");
1249 ALuint source
= This
->source
;
1251 if(This
->primary
->auxslot
!= 0)
1253 /* Simple hack to make reverb affect non-3D sounds too */
1254 alSource3i(source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1255 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1258 /* Non-3D sources aren't distance attenuated */
1259 This
->ds3dmode
= DS3DMODE_DISABLE
;
1260 alSource3f(source
, AL_POSITION
, 0.0f
, 1.0f
, 0.0f
);
1261 alSource3f(source
, AL_VELOCITY
, 0.0f
, 0.0f
, 0.0f
);
1262 alSource3f(source
, AL_DIRECTION
, 0.0f
, 0.0f
, 0.0f
);
1263 alSourcef(source
, AL_CONE_OUTER_GAIN
, 1.0f
);
1264 alSourcef(source
, AL_REFERENCE_DISTANCE
, 1.0f
);
1265 alSourcef(source
, AL_MAX_DISTANCE
, 1000.0f
);
1266 alSourcef(source
, AL_ROLLOFF_FACTOR
, 0.0f
);
1267 alSourcei(source
, AL_CONE_INNER_ANGLE
, 360);
1268 alSourcei(source
, AL_CONE_OUTER_ANGLE
, 360);
1269 alSourcei(source
, AL_SOURCE_RELATIVE
, AL_TRUE
);
1276 LeaveCriticalSection(This
->crst
);
1281 static HRESULT WINAPI
DS8Buffer_Lock(IDirectSoundBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1283 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1287 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1291 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1292 return DSERR_INVALIDPARAM
;
1295 EnterCriticalSection(This
->crst
);
1296 setALContext(This
->ctx
);
1300 if(ptr2
) *ptr2
= NULL
;
1303 hr
= DSERR_INVALIDPARAM
;
1304 if((flags
&DSBLOCK_FROMWRITECURSOR
))
1305 DS8Buffer_GetCurrentPosition(iface
, NULL
, &ofs
);
1306 else if(ofs
>= This
->buffer
->buf_size
)
1308 WARN("Invalid ofs %u\n", ofs
);
1311 if((flags
&DSBLOCK_ENTIREBUFFER
))
1312 bytes
= This
->buffer
->buf_size
;
1313 else if(bytes
> This
->buffer
->buf_size
)
1315 WARN("Invalid size %u\n", bytes
);
1319 *ptr1
= This
->buffer
->data
+ ofs
;
1320 if(ofs
+bytes
>= This
->buffer
->buf_size
)
1322 *len1
= This
->buffer
->buf_size
- ofs
;
1323 remain
= bytes
- *len1
;
1331 This
->buffer
->locked
= TRUE
;
1333 if(ptr2
&& len2
&& remain
)
1335 *ptr2
= This
->buffer
->data
;
1342 LeaveCriticalSection(This
->crst
);
1346 static HRESULT WINAPI
DS8Buffer_Play(IDirectSoundBuffer8
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1348 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1349 ALint type
, state
= AL_STOPPED
;
1353 TRACE("%p\n", This
);
1355 EnterCriticalSection(This
->crst
);
1356 setALContext(This
->ctx
);
1358 hr
= DSERR_BUFFERLOST
;
1359 if(This
->bufferlost
)
1361 WARN("Buffer %p lost\n", This
);
1365 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1367 if(!(This
->buffer
->dsbflags
&(DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCSOFTWARE
)))
1369 if(flags
& DSBPLAY_LOCSOFTWARE
)
1370 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1372 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1377 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This
->buffer
, prio
);
1378 hr
= DSERR_INVALIDPARAM
;
1382 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1383 if(This
->buffer
->numsegs
> 1)
1385 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1386 if(state
!= AL_PLAYING
&& This
->isplaying
)
1391 alGetSourcei(This
->source
, AL_SOURCE_TYPE
, &type
);
1392 alSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1397 if(state
== AL_PLAYING
)
1400 /* alSourceQueueBuffers will implicitly set type to streaming */
1401 if(This
->buffer
->numsegs
== 1)
1403 if(type
!= AL_STATIC
)
1404 alSourcei(This
->source
, AL_BUFFER
, This
->buffer
->buffers
[0]);
1405 alSourcePlay(This
->source
);
1407 if(alGetError() != AL_NO_ERROR
)
1409 ERR("Couldn't start source\n");
1410 This
->curidx
= (This
->buffer
->numsegs
-1+This
->curidx
)%This
->buffer
->numsegs
;
1411 alSourcei(This
->source
, AL_BUFFER
, 0);
1416 This
->isplaying
= TRUE
;
1420 DS8Buffer_addnotify(This
);
1421 DS8Buffer_starttimer(This
->primary
);
1423 else if(This
->buffer
->numsegs
> 1)
1424 DS8Buffer_starttimer(This
->primary
);
1428 LeaveCriticalSection(This
->crst
);
1432 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1434 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1436 TRACE("%p\n", This
);
1438 EnterCriticalSection(This
->crst
);
1439 setALContext(This
->ctx
);
1441 hr
= DSERR_INVALIDPARAM
;
1442 if(pos
>= This
->buffer
->buf_size
)
1445 if(This
->buffer
->numsegs
> 1)
1447 DS8Data
*buf
= This
->buffer
;
1448 This
->curidx
= pos
/buf
->segsize
;
1449 if(This
->curidx
>= buf
->numsegs
)
1450 This
->curidx
= buf
->numsegs
- 1;
1453 alSourceStop(This
->source
);
1454 alSourcei(This
->source
, AL_BUFFER
, 0);
1459 alSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1460 This
->lastpos
= pos
;
1465 LeaveCriticalSection(This
->crst
);
1469 static HRESULT WINAPI
DS8Buffer_SetFormat(IDirectSoundBuffer8
*iface
, const WAVEFORMATEX
*wfx
)
1471 /* This call only works on primary buffers */
1472 WARN("(%p)->(%p)\n", iface
, wfx
);
1473 return DSERR_INVALIDCALL
;
1476 static HRESULT WINAPI
DS8Buffer_SetVolume(IDirectSoundBuffer8
*iface
, LONG vol
)
1478 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1481 TRACE("(%p)->(%d)\n", iface
, vol
);
1483 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
1485 WARN("Invalid volume (%d)\n", vol
);
1486 return DSERR_INVALIDPARAM
;
1489 EnterCriticalSection(This
->crst
);
1490 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
1491 hr
= DSERR_CONTROLUNAVAIL
;
1494 ALfloat fvol
= mB_to_gain(vol
);
1495 setALContext(This
->ctx
);
1496 alSourcef(This
->source
, AL_GAIN
, fvol
);
1499 LeaveCriticalSection(This
->crst
);
1504 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1506 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1509 TRACE("(%p)->(%d)\n", iface
, pan
);
1511 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1513 WARN("invalid parameter: pan = %d\n", pan
);
1514 return DSERR_INVALIDPARAM
;
1517 EnterCriticalSection(This
->crst
);
1518 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1519 hr
= DSERR_CONTROLUNAVAIL
;
1523 pos
[0] = (pan
-DSBPAN_LEFT
) * 2.0 / (ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 1.0;
1524 /* NOTE: Strict movement along the X plane can cause the sound to jump
1525 * between left and right sharply. Using a curved path helps smooth it
1527 pos
[1] = sqrt(1.0 - pos
[0]*pos
[0]);
1530 setALContext(This
->ctx
);
1531 alSourcefv(This
->source
, AL_POSITION
, pos
);
1535 if(pan
!= 0 && This
->buffer
->format
.Format
.nChannels
> 1)
1536 FIXME("Panning for multi-channel buffers is not supported\n");
1538 LeaveCriticalSection(This
->crst
);
1543 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1545 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1548 TRACE("(%p)->(%u)\n", iface
, freq
);
1550 if(freq
< DSBFREQUENCY_MIN
|| freq
> DSBFREQUENCY_MAX
)
1552 WARN("invalid parameter: freq = %d\n", freq
);
1553 return DSERR_INVALIDPARAM
;
1556 EnterCriticalSection(This
->crst
);
1557 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1558 hr
= DSERR_CONTROLUNAVAIL
;
1561 ALfloat pitch
= 1.0f
;
1562 if(freq
!= DSBFREQUENCY_ORIGINAL
)
1563 pitch
= freq
/ (ALfloat
)This
->buffer
->format
.Format
.nSamplesPerSec
;
1565 setALContext(This
->ctx
);
1566 alSourcef(This
->source
, AL_PITCH
, pitch
);
1570 LeaveCriticalSection(This
->crst
);
1574 static HRESULT WINAPI
DS8Buffer_Stop(IDirectSoundBuffer8
*iface
)
1576 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1579 TRACE("(%p)->()\n", iface
);
1581 EnterCriticalSection(This
->crst
);
1582 setALContext(This
->ctx
);
1584 alSourcePause(This
->source
);
1586 /* Mac OS X doesn't immediately report state change
1587 * if Play() is immediately called after Stop, this can be fatal,
1588 * the buffer would never be restarted
1592 alGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1593 if(state
!= AL_PLAYING
)
1598 /* Stopped, remove from notify list */
1602 DWORD pos
= This
->lastpos
;
1603 hr
= IDirectSoundBuffer8_GetCurrentPosition(iface
, &pos
, NULL
);
1605 ERR("Own getcurrentposition failed!\n");
1606 trigger_notifies(This
, This
->lastpos
, pos
);
1607 This
->lastpos
= pos
;
1608 DS8Buffer_removenotify(This
);
1611 This
->isplaying
= FALSE
;
1614 LeaveCriticalSection(This
->crst
);
1619 static HRESULT WINAPI
DS8Buffer_Unlock(IDirectSoundBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1621 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1622 DS8Data
*buf
= This
->buffer
;
1623 DWORD bufsize
= buf
->buf_size
;
1624 DWORD_PTR ofs1
, ofs2
;
1625 DWORD_PTR boundary
= (DWORD_PTR
)buf
->data
;
1628 TRACE("(%p)->(%p, %u, %p, %u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1630 EnterCriticalSection(This
->crst
);
1631 setALContext(This
->ctx
);
1633 This
->buffer
->locked
= 0;
1634 hr
= DSERR_INVALIDPARAM
;
1636 /* Make sure offset is between boundary and boundary + bufsize */
1637 ofs1
= (DWORD_PTR
)ptr1
;
1638 ofs2
= (DWORD_PTR
)ptr2
;
1641 if(ofs2
&& ofs2
!= boundary
)
1645 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1654 if(This
->ExtAL
->BufferDataStatic
)
1657 if(This
->ExtAL
->BufferSubSamplesSOFT
)
1659 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1661 ptr1
= (BYTE
*)ptr1
- (ofs1
%format
->nBlockAlign
);
1662 ofs1
/= format
->nBlockAlign
;
1663 len1
/= format
->nBlockAlign
;
1665 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs1
, len1
,
1666 buf
->in_chans
, buf
->in_type
, ptr1
);
1667 ptr2
= (BYTE
*)ptr2
- (ofs2
%format
->nBlockAlign
);
1668 ofs2
/= format
->nBlockAlign
;
1669 len2
/= format
->nBlockAlign
;
1671 This
->ExtAL
->BufferSubSamplesSOFT(buf
->buffers
[0], ofs2
, len2
,
1672 buf
->in_chans
, buf
->in_type
, ptr2
);
1675 else if(This
->ExtAL
->BufferSubData
)
1677 WAVEFORMATEX
*format
= &buf
->format
.Format
;
1679 len1
-= len1
%format
->nBlockAlign
;
1681 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr1
,
1683 len2
-= len2
%format
->nBlockAlign
;
1685 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr2
,
1691 alBufferData(buf
->buffers
[0], buf
->buf_format
,
1692 buf
->data
, buf
->buf_size
,
1693 buf
->format
.Format
.nSamplesPerSec
);
1699 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1701 LeaveCriticalSection(This
->crst
);
1705 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1707 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1710 TRACE("(%p)->()\n", iface
);
1712 EnterCriticalSection(This
->crst
);
1713 if(This
->primary
->parent
->prio_level
< DSSCL_WRITEPRIMARY
||
1714 iface
== This
->primary
->write_emu
)
1716 This
->bufferlost
= 0;
1720 hr
= DSERR_BUFFERLOST
;
1721 LeaveCriticalSection(This
->crst
);
1726 static HRESULT WINAPI
DS8Buffer_SetFX(IDirectSoundBuffer8
*iface
, DWORD fxcount
, DSEFFECTDESC
*desc
, DWORD
*rescodes
)
1728 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1731 TRACE("(%p)->(%u, %p, %p)\n", This
, fxcount
, desc
, rescodes
);
1733 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFX
))
1735 WARN("FX control not set\n");
1736 return DSERR_CONTROLUNAVAIL
;
1741 if(desc
|| rescodes
)
1743 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1744 return DSERR_INVALIDPARAM
;
1747 /* No effects; we can handle that */
1751 if(!desc
|| !rescodes
)
1753 WARN("NULL desc and/or result pointer specified.\n");
1754 return DSERR_INVALIDPARAM
;
1757 /* We don't (currently) handle DSound effects */
1758 for(i
= 0;i
< fxcount
;++i
)
1760 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc
[i
].guidDSFXClass
));
1761 rescodes
[i
] = DSFXR_FAILED
;
1764 return DSERR_INVALIDPARAM
;
1767 static HRESULT WINAPI
DS8Buffer_AcquireResources(IDirectSoundBuffer8
*iface
, DWORD flags
, DWORD fxcount
, DWORD
*rescodes
)
1769 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1771 TRACE("(%p)->(%u, %u, %p)\n", This
, flags
, fxcount
, rescodes
);
1773 /* effects aren't supported at the moment.. */
1774 if(fxcount
!= 0 || rescodes
)
1776 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1777 return DSERR_INVALIDPARAM
;
1780 EnterCriticalSection(This
->crst
);
1781 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1783 This
->buffer
->dsbflags
&= ~(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
);
1784 if((flags
&DSBPLAY_LOCSOFTWARE
))
1785 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1787 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1789 LeaveCriticalSection(This
->crst
);
1794 static HRESULT WINAPI
DS8Buffer_GetObjectInPath(IDirectSoundBuffer8
*iface
, REFGUID guid
, DWORD idx
, REFGUID rguidiface
, void **ppv
)
1796 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface
, debugstr_guid(guid
), idx
, debugstr_guid(rguidiface
), ppv
);
1800 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
=
1802 DS8Buffer_QueryInterface
,
1806 DS8Buffer_GetCurrentPosition
,
1807 DS8Buffer_GetFormat
,
1808 DS8Buffer_GetVolume
,
1810 DS8Buffer_GetFrequency
,
1811 DS8Buffer_GetStatus
,
1812 DS8Buffer_Initialize
,
1815 DS8Buffer_SetCurrentPosition
,
1816 DS8Buffer_SetFormat
,
1817 DS8Buffer_SetVolume
,
1819 DS8Buffer_SetFrequency
,
1824 DS8Buffer_AcquireResources
,
1825 DS8Buffer_GetObjectInPath
1828 static inline DS8Buffer
*impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer
*iface
)
1830 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSound3DBuffer_iface
);
1833 static HRESULT WINAPI
DS8Buffer3D_QueryInterface(IDirectSound3DBuffer
*iface
, REFIID riid
, void **ppv
)
1835 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1836 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1839 static ULONG WINAPI
DS8Buffer3D_AddRef(IDirectSound3DBuffer
*iface
)
1841 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1844 InterlockedIncrement(&This
->all_ref
);
1845 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1846 TRACE("new refcount %d\n", ret
);
1851 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1853 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1856 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1857 TRACE("new refcount %d\n", ret
);
1858 if(InterlockedDecrement(&This
->all_ref
) == 0)
1859 DS8Buffer_Destroy(This
);
1864 static HRESULT WINAPI
DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer
*iface
, DS3DBUFFER
*ds3dbuffer
)
1866 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1870 TRACE("%p\n", This
);
1872 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
1874 WARN("Invalid parameters %p %u\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
1875 return DSERR_INVALIDPARAM
;
1877 ds3dbuf
.dwSize
= sizeof(ds3dbuf
);
1879 EnterCriticalSection(This
->crst
);
1880 setALContext(This
->ctx
);
1882 hr
= IDirectSound3DBuffer_GetPosition(iface
, &ds3dbuf
.vPosition
);
1884 hr
= IDirectSound3DBuffer_GetVelocity(iface
, &ds3dbuf
.vVelocity
);
1886 hr
= IDirectSound3DBuffer_GetConeAngles(iface
, &ds3dbuf
.dwInsideConeAngle
, &ds3dbuf
.dwOutsideConeAngle
);
1888 hr
= IDirectSound3DBuffer_GetConeOrientation(iface
, &ds3dbuf
.vConeOrientation
);
1890 hr
= IDirectSound3DBuffer_GetConeOutsideVolume(iface
, &ds3dbuf
.lConeOutsideVolume
);
1892 hr
= IDirectSound3DBuffer_GetMinDistance(iface
, &ds3dbuf
.flMinDistance
);
1894 hr
= IDirectSound3DBuffer_GetMaxDistance(iface
, &ds3dbuf
.flMaxDistance
);
1896 hr
= IDirectSound3DBuffer_GetMode(iface
, &ds3dbuf
.dwMode
);
1898 memcpy(ds3dbuffer
, &ds3dbuf
, sizeof(ds3dbuf
));
1901 LeaveCriticalSection(This
->crst
);
1906 static HRESULT WINAPI
DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer
*iface
, DWORD
*pdwInsideConeAngle
, DWORD
*pdwOutsideConeAngle
)
1908 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1909 ALint inangle
, outangle
;
1911 TRACE("(%p)->(%p, %p)\n", This
, pdwInsideConeAngle
, pdwOutsideConeAngle
);
1912 if(!pdwInsideConeAngle
|| !pdwOutsideConeAngle
)
1914 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle
, pdwOutsideConeAngle
);
1915 return DSERR_INVALIDPARAM
;
1918 EnterCriticalSection(This
->crst
);
1919 setALContext(This
->ctx
);
1921 alGetSourcei(This
->source
, AL_CONE_INNER_ANGLE
, &inangle
);
1922 alGetSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, &outangle
);
1924 *pdwInsideConeAngle
= inangle
;
1925 *pdwOutsideConeAngle
= outangle
;
1928 LeaveCriticalSection(This
->crst
);
1933 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1935 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1938 TRACE("(%p)->(%p)\n", This
, orient
);
1941 WARN("Invalid pointer\n");
1942 return DSERR_INVALIDPARAM
;
1945 EnterCriticalSection(This
->crst
);
1946 setALContext(This
->ctx
);
1948 alGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1952 orient
->z
= -dir
[2];
1955 LeaveCriticalSection(This
->crst
);
1960 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1962 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1965 TRACE("(%p)->(%p)\n", This
, vol
);
1968 WARN("Invalid pointer\n");
1969 return DSERR_INVALIDPARAM
;
1972 EnterCriticalSection(This
->crst
);
1973 setALContext(This
->ctx
);
1975 alGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1977 *vol
= gain_to_mB(gain
);
1978 *vol
= max(*vol
, DSBVOLUME_MIN
);
1979 *vol
= min(*vol
, DSBVOLUME_MAX
);
1982 LeaveCriticalSection(This
->crst
);
1986 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1988 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1991 TRACE("(%p)->(%p)\n", This
, maxdist
);
1994 WARN("Invalid pointer\n");
1995 return DSERR_INVALIDPARAM
;
1998 EnterCriticalSection(This
->crst
);
1999 setALContext(This
->ctx
);
2001 alGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
2006 LeaveCriticalSection(This
->crst
);
2011 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
2013 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2016 TRACE("(%p)->(%p)\n", This
, mindist
);
2019 WARN("Invalid pointer\n");
2020 return DSERR_INVALIDPARAM
;
2023 EnterCriticalSection(This
->crst
);
2024 setALContext(This
->ctx
);
2026 alGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
2031 LeaveCriticalSection(This
->crst
);
2036 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
2038 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2040 TRACE("(%p)->(%p)\n", This
, mode
);
2043 WARN("Invalid pointer\n");
2044 return DSERR_INVALIDPARAM
;
2047 EnterCriticalSection(This
->crst
);
2048 *mode
= This
->ds3dmode
;
2049 LeaveCriticalSection(This
->crst
);
2054 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
2056 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2059 TRACE("(%p)->(%p)\n", This
, pos
);
2062 WARN("Invalid pointer\n");
2063 return DSERR_INVALIDPARAM
;
2066 EnterCriticalSection(This
->crst
);
2067 setALContext(This
->ctx
);
2069 alGetSourcefv(This
->source
, AL_POSITION
, alpos
);
2076 LeaveCriticalSection(This
->crst
);
2081 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
2083 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2086 TRACE("(%p)->(%p)\n", This
, vel
);
2089 WARN("Invalid pointer\n");
2090 return DSERR_INVALIDPARAM
;
2093 EnterCriticalSection(This
->crst
);
2094 setALContext(This
->ctx
);
2096 alGetSourcefv(This
->source
, AL_VELOCITY
, alvel
);
2103 LeaveCriticalSection(This
->crst
);
2108 static HRESULT WINAPI
DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer
*iface
, const DS3DBUFFER
*ds3dbuffer
, DWORD apply
)
2110 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2111 TRACE("(%p)->(%p, %u)\n", This
, ds3dbuffer
, apply
);
2113 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
2115 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
2116 return DSERR_INVALIDPARAM
;
2119 if(ds3dbuffer
->dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2120 ds3dbuffer
->dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2122 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer
->dwInsideConeAngle
,
2123 ds3dbuffer
->dwOutsideConeAngle
);
2124 return DSERR_INVALIDPARAM
;
2127 if(ds3dbuffer
->lConeOutsideVolume
> DSBVOLUME_MAX
||
2128 ds3dbuffer
->lConeOutsideVolume
< DSBVOLUME_MIN
)
2130 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer
->lConeOutsideVolume
);
2131 return DSERR_INVALIDPARAM
;
2134 if(ds3dbuffer
->flMaxDistance
< 0.0f
)
2136 WARN("Invalid max distance (%f)\n", ds3dbuffer
->flMaxDistance
);
2137 return DSERR_INVALIDPARAM
;
2140 if(ds3dbuffer
->flMinDistance
< 0.0f
)
2142 WARN("Invalid min distance (%f)\n", ds3dbuffer
->flMinDistance
);
2143 return DSERR_INVALIDPARAM
;
2146 if(ds3dbuffer
->dwMode
!= DS3DMODE_NORMAL
&&
2147 ds3dbuffer
->dwMode
!= DS3DMODE_HEADRELATIVE
&&
2148 ds3dbuffer
->dwMode
!= DS3DMODE_DISABLE
)
2150 WARN("Invalid mode (%u)\n", ds3dbuffer
->dwMode
);
2151 return DSERR_INVALIDPARAM
;
2154 EnterCriticalSection(This
->crst
);
2155 setALContext(This
->ctx
);
2156 IDirectSound3DBuffer_SetPosition(iface
, ds3dbuffer
->vPosition
.x
, ds3dbuffer
->vPosition
.y
, ds3dbuffer
->vPosition
.z
, apply
);
2157 IDirectSound3DBuffer_SetVelocity(iface
, ds3dbuffer
->vVelocity
.x
, ds3dbuffer
->vVelocity
.y
, ds3dbuffer
->vVelocity
.z
, apply
);
2158 IDirectSound3DBuffer_SetConeAngles(iface
, ds3dbuffer
->dwInsideConeAngle
, ds3dbuffer
->dwOutsideConeAngle
, apply
);
2159 IDirectSound3DBuffer_SetConeOrientation(iface
, ds3dbuffer
->vConeOrientation
.x
, ds3dbuffer
->vConeOrientation
.y
, ds3dbuffer
->vConeOrientation
.z
, apply
);
2160 IDirectSound3DBuffer_SetConeOutsideVolume(iface
, ds3dbuffer
->lConeOutsideVolume
, apply
);
2161 IDirectSound3DBuffer_SetMinDistance(iface
, ds3dbuffer
->flMinDistance
, apply
);
2162 IDirectSound3DBuffer_SetMaxDistance(iface
, ds3dbuffer
->flMaxDistance
, apply
);
2163 IDirectSound3DBuffer_SetMode(iface
, ds3dbuffer
->dwMode
, apply
);
2165 LeaveCriticalSection(This
->crst
);
2170 static HRESULT WINAPI
DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer
*iface
, DWORD dwInsideConeAngle
, DWORD dwOutsideConeAngle
, DWORD apply
)
2172 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2174 TRACE("(%p)->(%u, %u, %u)\n", This
, dwInsideConeAngle
, dwOutsideConeAngle
, apply
);
2175 if(dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2176 dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2178 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle
, dwOutsideConeAngle
);
2179 return DSERR_INVALIDPARAM
;
2182 EnterCriticalSection(This
->crst
);
2183 if(apply
== DS3D_DEFERRED
)
2185 This
->ds3dbuffer
.dwInsideConeAngle
= dwInsideConeAngle
;
2186 This
->ds3dbuffer
.dwOutsideConeAngle
= dwOutsideConeAngle
;
2187 This
->dirty
.bit
.cone_angles
= 1;
2191 setALContext(This
->ctx
);
2192 alSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
2193 alSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
2197 LeaveCriticalSection(This
->crst
);
2202 static HRESULT WINAPI
DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2204 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2206 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2208 EnterCriticalSection(This
->crst
);
2209 if(apply
== DS3D_DEFERRED
)
2211 This
->ds3dbuffer
.vConeOrientation
.x
= x
;
2212 This
->ds3dbuffer
.vConeOrientation
.y
= y
;
2213 This
->ds3dbuffer
.vConeOrientation
.z
= z
;
2214 This
->dirty
.bit
.cone_orient
= 1;
2218 setALContext(This
->ctx
);
2219 alSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
2223 LeaveCriticalSection(This
->crst
);
2228 static HRESULT WINAPI
DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG vol
, DWORD apply
)
2230 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2232 TRACE("(%p)->(%u, %u)\n", This
, vol
, apply
);
2233 if(vol
< DSBVOLUME_MIN
|| vol
> DSBVOLUME_MAX
)
2235 WARN("Invalid volume (%u)\n", vol
);
2236 return DSERR_INVALIDPARAM
;
2239 EnterCriticalSection(This
->crst
);
2240 if(apply
== DS3D_DEFERRED
)
2242 This
->ds3dbuffer
.lConeOutsideVolume
= vol
;
2243 This
->dirty
.bit
.cone_outsidevolume
= 1;
2247 setALContext(This
->ctx
);
2248 alSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
2252 LeaveCriticalSection(This
->crst
);
2257 static HRESULT WINAPI
DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE maxdist
, DWORD apply
)
2259 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2261 TRACE("(%p)->(%f, %u)\n", This
, maxdist
, apply
);
2264 WARN("Invalid max distance (%f)\n", maxdist
);
2265 return DSERR_INVALIDPARAM
;
2268 EnterCriticalSection(This
->crst
);
2269 if(apply
== DS3D_DEFERRED
)
2271 This
->ds3dbuffer
.flMaxDistance
= maxdist
;
2272 This
->dirty
.bit
.max_distance
= 1;
2276 setALContext(This
->ctx
);
2277 alSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
2281 LeaveCriticalSection(This
->crst
);
2286 static HRESULT WINAPI
DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE mindist
, DWORD apply
)
2288 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2290 TRACE("(%p)->(%f, %u)\n", This
, mindist
, apply
);
2293 WARN("Invalid min distance (%f)\n", mindist
);
2294 return DSERR_INVALIDPARAM
;
2297 EnterCriticalSection(This
->crst
);
2298 if(apply
== DS3D_DEFERRED
)
2300 This
->ds3dbuffer
.flMinDistance
= mindist
;
2301 This
->dirty
.bit
.min_distance
= 1;
2305 setALContext(This
->ctx
);
2306 alSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
2310 LeaveCriticalSection(This
->crst
);
2315 static HRESULT WINAPI
DS8Buffer3D_SetMode(IDirectSound3DBuffer
*iface
, DWORD mode
, DWORD apply
)
2317 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2319 TRACE("(%p)->(%u, %u)\n", This
, mode
, apply
);
2320 if(mode
!= DS3DMODE_NORMAL
&& mode
!= DS3DMODE_HEADRELATIVE
&&
2321 mode
!= DS3DMODE_DISABLE
)
2323 WARN("Invalid mode (%u)\n", mode
);
2324 return DSERR_INVALIDPARAM
;
2327 EnterCriticalSection(This
->crst
);
2328 if(apply
== DS3D_DEFERRED
)
2330 This
->ds3dbuffer
.dwMode
= mode
;
2331 This
->dirty
.bit
.mode
= 1;
2335 setALContext(This
->ctx
);
2336 alSourcei(This
->source
, AL_SOURCE_RELATIVE
,
2337 (mode
!= DS3DMODE_NORMAL
) ? AL_TRUE
: AL_FALSE
);
2338 alSourcef(This
->source
, AL_ROLLOFF_FACTOR
,
2339 (mode
== DS3DMODE_DISABLE
) ? 0.0f
: This
->primary
->rollofffactor
);
2340 This
->ds3dmode
= mode
;
2344 LeaveCriticalSection(This
->crst
);
2349 static HRESULT WINAPI
DS8Buffer3D_SetPosition(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2351 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2353 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2355 EnterCriticalSection(This
->crst
);
2356 if(apply
== DS3D_DEFERRED
)
2358 This
->ds3dbuffer
.vPosition
.x
= x
;
2359 This
->ds3dbuffer
.vPosition
.y
= y
;
2360 This
->ds3dbuffer
.vPosition
.z
= z
;
2361 This
->dirty
.bit
.pos
= 1;
2365 setALContext(This
->ctx
);
2366 alSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
2370 LeaveCriticalSection(This
->crst
);
2375 static HRESULT WINAPI
DS8Buffer3D_SetVelocity(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2377 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2379 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2381 EnterCriticalSection(This
->crst
);
2382 if(apply
== DS3D_DEFERRED
)
2384 This
->ds3dbuffer
.vVelocity
.x
= x
;
2385 This
->ds3dbuffer
.vVelocity
.y
= y
;
2386 This
->ds3dbuffer
.vVelocity
.z
= z
;
2387 This
->dirty
.bit
.vel
= 1;
2391 setALContext(This
->ctx
);
2392 alSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
2396 LeaveCriticalSection(This
->crst
);
2401 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2403 DS8Buffer3D_QueryInterface
,
2405 DS8Buffer3D_Release
,
2406 DS8Buffer3D_GetAllParameters
,
2407 DS8Buffer3D_GetConeAngles
,
2408 DS8Buffer3D_GetConeOrientation
,
2409 DS8Buffer3D_GetConeOutsideVolume
,
2410 DS8Buffer3D_GetMaxDistance
,
2411 DS8Buffer3D_GetMinDistance
,
2412 DS8Buffer3D_GetMode
,
2413 DS8Buffer3D_GetPosition
,
2414 DS8Buffer3D_GetVelocity
,
2415 DS8Buffer3D_SetAllParameters
,
2416 DS8Buffer3D_SetConeAngles
,
2417 DS8Buffer3D_SetConeOrientation
,
2418 DS8Buffer3D_SetConeOutsideVolume
,
2419 DS8Buffer3D_SetMaxDistance
,
2420 DS8Buffer3D_SetMinDistance
,
2421 DS8Buffer3D_SetMode
,
2422 DS8Buffer3D_SetPosition
,
2423 DS8Buffer3D_SetVelocity
2426 static inline DS8Buffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
2428 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundNotify_iface
);
2431 static HRESULT WINAPI
DS8BufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
2433 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2434 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2437 static ULONG WINAPI
DS8BufferNot_AddRef(IDirectSoundNotify
*iface
)
2439 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2442 InterlockedIncrement(&This
->all_ref
);
2443 ret
= InterlockedIncrement(&This
->not_ref
);
2444 TRACE("new refcount %d\n", ret
);
2449 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2451 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2454 ret
= InterlockedDecrement(&This
->not_ref
);
2455 TRACE("new refcount %d\n", ret
);
2456 if(InterlockedDecrement(&This
->all_ref
) == 0)
2457 DS8Buffer_Destroy(This
);
2462 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2464 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2465 DSBPOSITIONNOTIFY
*nots
;
2469 EnterCriticalSection(This
->crst
);
2470 hr
= DSERR_INVALIDPARAM
;
2471 if(count
&& !notifications
)
2474 hr
= IDirectSoundBuffer8_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2478 hr
= DSERR_INVALIDCALL
;
2479 if((state
&DSBSTATUS_PLAYING
))
2484 HeapFree(GetProcessHeap(), 0, This
->notify
);
2493 hr
= DSERR_INVALIDPARAM
;
2494 for(i
= 0;i
< count
;++i
)
2496 if(notifications
[i
].dwOffset
>= This
->buffer
->buf_size
&&
2497 notifications
[i
].dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
2502 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2505 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2507 HeapFree(GetProcessHeap(), 0, This
->notify
);
2508 This
->notify
= nots
;
2509 This
->nnotify
= count
;
2515 LeaveCriticalSection(This
->crst
);
2519 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
=
2521 DS8BufferNot_QueryInterface
,
2522 DS8BufferNot_AddRef
,
2523 DS8BufferNot_Release
,
2524 DS8BufferNot_SetNotificationPositions
2527 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2528 handled through secondary buffers. */
2529 static inline DS8Buffer
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
2531 return CONTAINING_RECORD(iface
, DS8Buffer
, IKsPropertySet_iface
);
2534 static HRESULT WINAPI
DS8BufferProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
2536 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2537 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2540 static ULONG WINAPI
DS8BufferProp_AddRef(IKsPropertySet
*iface
)
2542 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2545 InterlockedIncrement(&This
->all_ref
);
2546 ret
= InterlockedIncrement(&This
->prop_ref
);
2547 TRACE("new refcount %d\n", ret
);
2552 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2554 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2557 ret
= InterlockedDecrement(&This
->prop_ref
);
2558 TRACE("new refcount %d\n", ret
);
2559 if(InterlockedDecrement(&This
->all_ref
) == 0)
2560 DS8Buffer_Destroy(This
);
2565 static HRESULT WINAPI
DS8BufferProp_Get(IKsPropertySet
*iface
,
2566 REFGUID guidPropSet
, ULONG dwPropID
,
2567 LPVOID pInstanceData
, ULONG cbInstanceData
,
2568 LPVOID pPropData
, ULONG cbPropData
,
2571 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2572 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2574 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface
, debugstr_guid(guidPropSet
),
2575 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
2582 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2588 /* Not a known buffer/source property. Pass it to the listener */
2589 hr
= IKsPropertySet_Get(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2590 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
,
2597 static HRESULT WINAPI
DS8BufferProp_Set(IKsPropertySet
*iface
,
2598 REFGUID guidPropSet
, ULONG dwPropID
,
2599 LPVOID pInstanceData
, ULONG cbInstanceData
,
2600 LPVOID pPropData
, ULONG cbPropData
)
2602 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2603 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2605 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface
, debugstr_guid(guidPropSet
),
2606 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
2609 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2615 /* Not a known buffer/source property. Pass it to the listener */
2616 hr
= IKsPropertySet_Set(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2617 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
,
2624 static HRESULT WINAPI
DS8BufferProp_QuerySupport(IKsPropertySet
*iface
,
2625 REFGUID guidPropSet
, ULONG dwPropID
,
2626 PULONG pTypeSupport
)
2628 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2629 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2631 TRACE("(%p)->(%s, %u, %p)\n", iface
, debugstr_guid(guidPropSet
), dwPropID
, pTypeSupport
);
2638 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_BufferProperties
))
2644 /* Not a known buffer/source property. Pass it to the listener */
2645 hr
= IKsPropertySet_QuerySupport(&This
->primary
->IKsPropertySet_iface
,
2646 guidPropSet
, dwPropID
, pTypeSupport
);
2652 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2654 DS8BufferProp_QueryInterface
,
2655 DS8BufferProp_AddRef
,
2656 DS8BufferProp_Release
,
2659 DS8BufferProp_QuerySupport