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"
41 #include "dsound_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
48 /* TODO: when bufferlost is set, return from all calls except initialize with
51 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
;
52 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
;
53 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
;
54 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
;
56 /* Amount of buffers that have to be queued when
57 * bufferdatastatic and buffersubdata are not available */
64 /* Lock was called and unlock isn't? */
77 ALuint buggy_app_detection
;
80 static void trigger_notifies(DS8Buffer
*buf
, DWORD lastpos
, DWORD curpos
, BOOL stopping
)
83 if (lastpos
== curpos
&& !stopping
)
85 for (i
= 0; i
< buf
->nnotify
; ++i
)
87 DSBPOSITIONNOTIFY
*not = &buf
->notify
[i
];
88 HANDLE event
= not->hEventNotify
;
89 DWORD ofs
= not->dwOffset
;
91 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
)
115 DS8Primary
*prim
= (DS8Primary
*)dwUser
;
120 EnterCriticalSection(&prim
->crst
);
121 setALContext(prim
->ctx
);
123 /* OpenAL doesn't support our lovely buffer extensions
124 * so just make sure enough buffers are queued
126 if(!prim
->ExtAL
.BufferSubData
&& !prim
->ExtAL
.BufferDataStatic
)
128 /* FIXME: Should probably use this logic to also
129 * call trigger_notifies
131 for (i
= 0; i
< prim
->nbuffers
; ++i
)
133 DS8Buffer
*buf
= prim
->buffers
[i
];
134 ALint done
= 0, queued
= QBUFFERS
, state
= AL_PLAYING
;
137 if (buf
->buffer
->numsegs
== 1 || !buf
->isplaying
)
140 palGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
141 palGetSourcei(buf
->source
, AL_BUFFERS_QUEUED
, &queued
);
142 palGetSourcei(buf
->source
, AL_BUFFERS_PROCESSED
, &done
);
146 palSourceUnqueueBuffers(buf
->source
, 1, &which
);
147 while (queued
< QBUFFERS
)
149 which
= buf
->buffer
->buffers
[buf
->curidx
];
150 ofs
= buf
->curidx
*buf
->buffer
->segsize
;
151 if(buf
->curidx
< buf
->buffer
->numsegs
-1)
152 palBufferData(which
, buf
->buffer
->buf_format
,
153 buf
->buffer
->data
+ ofs
, buf
->buffer
->segsize
,
154 buf
->buffer
->format
->nSamplesPerSec
);
156 palBufferData(which
, buf
->buffer
->buf_format
,
157 buf
->buffer
->data
+ ofs
, buf
->buffer
->lastsegsize
,
158 buf
->buffer
->format
->nSamplesPerSec
);
160 palSourceQueueBuffers(buf
->source
, 1, &which
);
161 buf
->curidx
= (buf
->curidx
+1)%buf
->buffer
->numsegs
;
164 if (!buf
->curidx
&& !buf
->islooping
)
166 buf
->isplaying
= FALSE
;
170 if (state
!= AL_PLAYING
)
174 IDirectSoundBuffer8_Stop(&buf
->IDirectSoundBuffer8_iface
);
177 palSourcePlay(buf
->source
);
183 IAudioClient_GetCurrentPadding(prim
->dev
, &pad
);
185 if(pad
&& !prim
->ExtAL
.BufferDataStatic
&& prim
->ExtAL
.BufferSubData
)
187 for (i
= 0; i
< prim
->nbuffers
; ++i
)
189 DS8Buffer
*buf
= prim
->buffers
[i
];
191 DWORD pos1
, pos2
, ofs
;
193 if (!buf
->buffer
->buggy_app_detection
)
195 palGetSourcei(buf
->source
, AL_SOURCE_STATE
, &state
);
196 if (state
!= AL_PLAYING
)
198 EnterCriticalSection(buf
->crst
);
199 WARN("Unlock never was called succesfully, doing this manually now\n");
200 IDirectSoundBuffer8_GetCurrentPosition(&buf
->IDirectSoundBuffer8_iface
, &ofs
, NULL
);
201 IDirectSoundBuffer8_Lock(&buf
->IDirectSoundBuffer8_iface
, ofs
, pad
* buf
->buffer
->format
->nBlockAlign
, &ptr1
, &pos1
, &ptr2
, &pos2
, 0);
202 IDirectSoundBuffer8_Unlock(&buf
->IDirectSoundBuffer8_iface
, ptr1
, pos1
, ptr2
, pos2
);
203 buf
->buffer
->buggy_app_detection
= 1;
204 LeaveCriticalSection(buf
->crst
);
209 IAudioRenderClient_GetBuffer(prim
->render_dev
, pad
, &data
);
210 palcRenderSamplesSOFT(prim
->parent
->device
, data
, pad
);
211 IAudioRenderClient_ReleaseBuffer(prim
->render_dev
, pad
, 0);
214 for (i
= 0; i
< prim
->nnotifies
; )
216 DS8Buffer
*buf
= prim
->notifies
[i
];
217 IDirectSoundBuffer8
*dsb
= &buf
->IDirectSoundBuffer8_iface
;
218 DWORD status
, curpos
;
221 hr
= IDirectSoundBuffer8_GetStatus(dsb
, &status
);
224 if (!(status
& DSBSTATUS_PLAYING
))
226 /* Stop will remove this buffer from list,
227 * and put another at the current position
230 IDirectSoundBuffer8_Stop(dsb
);
233 hr
= IDirectSoundBuffer8_GetCurrentPosition(dsb
, &curpos
, NULL
);
236 trigger_notifies(buf
, buf
->lastpos
, curpos
, FALSE
);
237 buf
->lastpos
= curpos
;
243 LeaveCriticalSection(&prim
->crst
);
246 static void DS8Buffer_starttimer(DS8Primary
*prim
)
249 DWORD triggertime
, res
= DS_TIME_RES
;
250 INT64 default_period
, min_period
;
255 timeGetDevCaps(&time
, sizeof(TIMECAPS
));
256 IAudioClient_GetDevicePeriod(prim
->dev
, &default_period
, &min_period
);
257 triggertime
= default_period
/ 10000;
258 getALCError(prim
->parent
->device
);
259 if(triggertime
< time
.wPeriodMin
)
260 triggertime
= time
.wPeriodMin
;
261 TRACE("Calling timer every %u ms\n", triggertime
);
262 if (res
< time
.wPeriodMin
)
263 res
= time
.wPeriodMin
;
264 if (timeBeginPeriod(res
) == TIMERR_NOCANDO
)
265 WARN("Could not set minimum resolution, don't expect sound\n");
266 prim
->timer_res
= res
;
267 prim
->timer_id
= timeSetEvent(triggertime
, res
, DS8Buffer_timer
, (DWORD_PTR
)prim
, TIME_PERIODIC
| TIME_KILL_SYNCHRONOUS
);
268 IAudioClient_Start(prim
->dev
);
271 /* Should be called with critsect held and context set.. */
272 static void DS8Buffer_addnotify(DS8Buffer
*buf
)
277 list
= buf
->primary
->notifies
;
278 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
282 ERR("Buffer %p already in notification list\n", buf
);
286 if(buf
->primary
->nnotifies
== buf
->primary
->sizenotifies
)
288 list
= HeapReAlloc(GetProcessHeap(), 0, list
, (buf
->primary
->nnotifies
+ 1) * sizeof(*list
));
291 buf
->primary
->sizenotifies
++;
293 list
[buf
->primary
->nnotifies
++] = buf
;
294 buf
->primary
->notifies
= list
;
297 static void DS8Buffer_removenotify(DS8Buffer
*buf
)
300 for(i
= 0; i
< buf
->primary
->nnotifies
; ++i
)
302 if(buf
== buf
->primary
->notifies
[i
])
304 buf
->primary
->notifies
[i
] =
305 buf
->primary
->notifies
[--buf
->primary
->nnotifies
];
311 static const char *get_fmtstr_PCM(const WAVEFORMATEX
*format
, WAVEFORMATEX
**out
)
313 *out
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
));
314 if(!*out
) return NULL
;
319 if(format
->nChannels
> 2 && !palIsExtensionPresent("AL_EXT_MCFORMATS"))
321 WARN("Extension AL_EXT_MCFORMATS not available, cannot enumerate > 2 channels\n");
325 if(format
->wBitsPerSample
== 8)
327 switch(format
->nChannels
)
329 case 1: return "AL_FORMAT_MONO8";
330 case 2: return "AL_FORMAT_STEREO8";
331 case 4: return "AL_FORMAT_QUAD8";
332 case 6: return "AL_FORMAT_51CHN8";
333 case 7: return "AL_FORMAT_61CHN8";
334 case 8: return "AL_FORMAT_71CHN8";
338 else if(format
->wBitsPerSample
== 16)
340 switch(format
->nChannels
)
342 case 1: return "AL_FORMAT_MONO16";
343 case 2: return "AL_FORMAT_STEREO16";
344 case 4: return "AL_FORMAT_QUAD16";
345 case 6: return "AL_FORMAT_51CHN16";
346 case 7: return "AL_FORMAT_61CHN16";
347 case 8: return "AL_FORMAT_71CHN16";
354 if((format
->wBitsPerSample
%8) == 0)
355 ERR("Could not get OpenAL format (%d-bit, %d channels)\n",
356 format
->wBitsPerSample
, format
->nChannels
);
360 /* Speaker configs */
361 #define MONO SPEAKER_FRONT_CENTER
362 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
363 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
364 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
365 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
366 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
367 #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)
369 static const char *get_fmtstr_EXT(const WAVEFORMATEX
*format
, WAVEFORMATEX
**out
)
371 WAVEFORMATEXTENSIBLE
*wfe
;
373 if(format
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
))
375 WARN("Invalid cbSize specified for WAVE_FORMAT_EXTENSIBLE (%d)\n", format
->cbSize
);
379 wfe
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE
));
380 if(!wfe
) return NULL
;
382 *wfe
= *(WAVEFORMATEXTENSIBLE
*)format
;
383 wfe
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
);
386 TRACE("Extensible values:\n"
388 " ChannelMask = %#x\n"
390 wfe
->Samples
.wReserved
, wfe
->dwChannelMask
,
391 debugstr_guid(&wfe
->SubFormat
));
393 if(!wfe
->Samples
.wValidBitsPerSample
)
394 wfe
->Samples
.wValidBitsPerSample
= wfe
->Format
.wBitsPerSample
;
396 if(wfe
->dwChannelMask
!= MONO
&& wfe
->dwChannelMask
!= STEREO
&&
397 !palIsExtensionPresent("AL_EXT_MCFORMATS"))
399 /* QUAD PCM might still work, special case */
400 if(palIsExtensionPresent("AL_LOKI_quadriphonic") &&
401 IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) &&
402 wfe
->dwChannelMask
== QUAD
)
404 if(wfe
->Samples
.wValidBitsPerSample
== 16)
405 return "AL_FORMAT_QUAD16_LOKI";
406 else if(wfe
->Samples
.wValidBitsPerSample
== 8)
407 return "AL_FORMAT_QUAD8_LOKI";
409 WARN("Not all formats available\n");
413 if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
415 if(wfe
->Samples
.wValidBitsPerSample
== 8)
417 switch(wfe
->dwChannelMask
)
419 case MONO
: return "AL_FORMAT_MONO8";
420 case STEREO
: return "AL_FORMAT_STEREO8";
421 case REAR
: return "AL_FORMAT_REAR8";
422 case QUAD
: return "AL_FORMAT_QUAD8";
423 case X5DOT1
: return "AL_FORMAT_51CHN8";
424 case X6DOT1
: return "AL_FORMAT_61CHN8";
425 case X7DOT1
: return "AL_FORMAT_71CHN8";
429 else if(wfe
->Samples
.wValidBitsPerSample
== 16)
431 switch(wfe
->dwChannelMask
)
433 case MONO
: return "AL_FORMAT_MONO16";
434 case STEREO
: return "AL_FORMAT_STEREO16";
435 case REAR
: return "AL_FORMAT_REAR16";
436 case QUAD
: return "AL_FORMAT_QUAD16";
437 case X5DOT1
: return "AL_FORMAT_51CHN16";
438 case X6DOT1
: return "AL_FORMAT_61CHN16";
439 case X7DOT1
: return "AL_FORMAT_71CHN16";
443 #if 1 /* TODO: Ugly freaky hack just to pass tests */
444 else if(wfe
->Samples
.wValidBitsPerSample
== 24 ||
445 wfe
->Samples
.wValidBitsPerSample
== 32)
447 switch(wfe
->dwChannelMask
)
449 case MONO
: return "AL_FORMAT_MONO_FLOAT32";
450 case STEREO
: return "AL_FORMAT_STEREO_FLOAT32";
451 case REAR
: return "AL_FORMAT_REAR32";
452 case QUAD
: return "AL_FORMAT_QUAD32";
453 case X5DOT1
: return "AL_FORMAT_51CHN32";
454 case X6DOT1
: return "AL_FORMAT_61CHN32";
455 case X7DOT1
: return "AL_FORMAT_71CHN32";
460 else if((wfe
->Samples
.wValidBitsPerSample
%8) == 0)
461 ERR("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
462 wfe
->Samples
.wValidBitsPerSample
, wfe
->dwChannelMask
);
465 else if(IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
466 palIsExtensionPresent("AL_EXT_float32"))
468 if(wfe
->Samples
.wValidBitsPerSample
!= 32)
470 WARN("Invalid valid bits %u/32\n", wfe
->Samples
.wValidBitsPerSample
);
473 switch(wfe
->dwChannelMask
)
475 case MONO
: return "AL_FORMAT_MONO_FLOAT32";
476 case STEREO
: return "AL_FORMAT_STEREO_FLOAT32";
477 case REAR
: return "AL_FORMAT_REAR32";
478 case QUAD
: return "AL_FORMAT_QUAD32";
479 case X5DOT1
: return "AL_FORMAT_51CHN32";
480 case X6DOT1
: return "AL_FORMAT_61CHN32";
481 case X7DOT1
: return "AL_FORMAT_71CHN32";
483 ERR("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
484 wfe
->Samples
.wValidBitsPerSample
, wfe
->dwChannelMask
);
488 else if(!IsEqualGUID(&wfe
->SubFormat
, &GUID_NULL
))
489 ERR("Unhandled extensible format: %s\n", debugstr_guid(&wfe
->SubFormat
));
493 static const char *get_fmtstr_FLOAT(const WAVEFORMATEX
*format
, WAVEFORMATEX
**out
)
495 if (!palIsExtensionPresent("AL_EXT_float32"))
498 *out
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
));
499 if(!*out
) return NULL
;
504 switch(format
->nChannels
)
506 case 1: return "AL_FORMAT_MONO_FLOAT32";
507 case 2: return "AL_FORMAT_STEREO_FLOAT32";
513 static HRESULT
openal_format(const WAVEFORMATEX
*format
, WAVEFORMATEX
**myformat
, ALenum
*enumformat
)
516 HRESULT hr
= DSERR_INVALIDPARAM
;
519 if(format
->wFormatTag
== WAVE_FORMAT_PCM
)
520 fmt_str
= get_fmtstr_PCM(format
, myformat
);
521 else if(format
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
523 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)format
;
525 hr
= DSERR_CONTROLUNAVAIL
;
526 if(format
->cbSize
> sizeof(WAVEFORMATEXTENSIBLE
)-sizeof(WAVEFORMATEX
) &&
527 format
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
))
530 hr
= DSERR_INVALIDPARAM
;
531 if(!IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
532 !IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))
535 fmt_str
= get_fmtstr_EXT(format
, myformat
);
537 else if(format
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
)
539 fmt_str
= get_fmtstr_FLOAT(format
, myformat
);
543 ERR("Unhandled formattag 0x%04x\n", format
->wFormatTag
);
544 return DSERR_INVALIDPARAM
;
550 *enumformat
= palGetEnumValue(fmt_str
);
551 if(palGetError() != AL_NO_ERROR
|| *enumformat
== 0 || *enumformat
== -1)
556 WARN("Could not get OpenAL format from %s\n", fmt_str
);
558 HeapFree(GetProcessHeap(), 0, *myformat
);
563 static void DS8Data_Release(DS8Data
*This
);
564 static HRESULT
DS8Data_Create(DS8Data
**ppv
, const DSBUFFERDESC
*desc
, DS8Primary
*prim
)
566 HRESULT hr
= DSERR_INVALIDPARAM
;
567 WAVEFORMATEX
*format
;
570 format
= desc
->lpwfxFormat
;
571 TRACE("Requested buffer format:\n"
574 " SamplesPerSec = %u\n"
575 " AvgBytesPerSec = %u\n"
577 " BitsPerSample = %d\n",
578 format
->wFormatTag
, format
->nChannels
,
579 format
->nSamplesPerSec
, format
->nAvgBytesPerSec
,
580 format
->nBlockAlign
, format
->wBitsPerSample
);
582 if(format
->nBlockAlign
== 0)
584 WARN("Invalid BlockAlign specified\n");
585 return DSERR_INVALIDPARAM
;
588 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
589 * will need the EAX-RAM extension. Currently, we just tell the app it
590 * gets what it wanted. */
591 pBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
));
593 return E_OUTOFMEMORY
;
596 pBuffer
->dsbflags
= desc
->dwFlags
;
597 if((pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
)) == (DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
))
599 WARN("Hardware and software location requested\n");
602 if(!(pBuffer
->dsbflags
&(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCDEFER
)))
603 pBuffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
605 pBuffer
->buf_size
= desc
->dwBufferBytes
+ format
->nBlockAlign
- 1;
606 pBuffer
->buf_size
-= pBuffer
->buf_size
%format
->nBlockAlign
;
608 hr
= DSERR_BUFFERTOOSMALL
;
609 if(pBuffer
->buf_size
< DSBSIZE_MIN
)
612 hr
= DSERR_INVALIDPARAM
;
613 if(pBuffer
->buf_size
> DSBSIZE_MAX
)
616 pBuffer
->numsegs
= 1;
617 pBuffer
->segsize
= pBuffer
->buf_size
;
618 pBuffer
->lastsegsize
= pBuffer
->buf_size
;
620 if(!(pBuffer
->dsbflags
& DSBCAPS_STATIC
) && !prim
->ExtAL
.BufferSubData
621 && !prim
->ExtAL
.BufferDataStatic
)
623 ALCint refresh
= FAKE_REFRESH_COUNT
;
626 palcGetIntegerv(prim
->parent
->device
, ALC_REFRESH
, 1, &refresh
);
627 getALCError(prim
->parent
->device
);
629 newSize
= format
->nAvgBytesPerSec
/refresh
+ format
->nBlockAlign
- 1;
630 newSize
-= newSize
%format
->nBlockAlign
;
632 /* Make sure enough buffers are available */
633 if(newSize
> pBuffer
->buf_size
/(QBUFFERS
+2))
634 ERR("Buffer segments too large to stream (%u for %u)!\n",
635 newSize
, pBuffer
->buf_size
);
638 pBuffer
->numsegs
= pBuffer
->buf_size
/newSize
;
639 pBuffer
->segsize
= newSize
;
640 pBuffer
->lastsegsize
= pBuffer
->buf_size
- (newSize
*(pBuffer
->numsegs
-1));
641 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
642 pBuffer
->numsegs
, pBuffer
->segsize
, pBuffer
->lastsegsize
);
646 hr
= openal_format(format
, &pBuffer
->format
, &pBuffer
->buf_format
);
651 pBuffer
->buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pBuffer
->buffers
)*pBuffer
->numsegs
);
652 pBuffer
->data
= HeapAlloc(GetProcessHeap(), 0, pBuffer
->buf_size
);
653 if(!pBuffer
->buffers
|| !pBuffer
->data
)
656 palGenBuffers(pBuffer
->numsegs
, pBuffer
->buffers
);
663 DS8Data_Release(pBuffer
);
667 static void DS8Data_AddRef(DS8Data
*data
)
669 InterlockedIncrement(&data
->ref
);
672 /* This function is always called with the device lock held */
673 static void DS8Data_Release(DS8Data
*This
)
675 if(InterlockedDecrement(&This
->ref
)) return;
677 TRACE("Deleting %p\n", This
);
678 if (This
->buffers
&& This
->data
&& This
->buffers
[0])
680 palDeleteBuffers(This
->numsegs
, This
->buffers
);
683 HeapFree(GetProcessHeap(), 0, This
->buffers
);
684 HeapFree(GetProcessHeap(), 0, This
->data
);
685 HeapFree(GetProcessHeap(), 0, This
->format
);
686 HeapFree(GetProcessHeap(), 0, This
);
689 HRESULT
DS8Buffer_Create(DS8Buffer
**ppv
, DS8Primary
*parent
, DS8Buffer
*orig
)
691 HRESULT hr
= DSERR_OUTOFMEMORY
;
696 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
699 This
->primary
= parent
;
700 This
->IDirectSoundBuffer8_iface
.lpVtbl
= &DS8Buffer_Vtbl
;
701 This
->IDirectSound3DBuffer_iface
.lpVtbl
= &DS8Buffer3d_Vtbl
;
702 This
->IDirectSoundNotify_iface
.lpVtbl
= &DS8BufferNot_Vtbl
;
703 This
->IKsPropertySet_iface
.lpVtbl
= &DS8BufferProp_Vtbl
;
704 This
->ctx
= parent
->ctx
;
705 This
->ExtAL
= &parent
->ExtAL
;
706 This
->crst
= &parent
->crst
;
707 This
->ref
= This
->all_ref
= 1;
711 This
->buffer
= orig
->buffer
;
712 DS8Data_AddRef(This
->buffer
);
715 /* Append to buffer list */
716 bufs
= parent
->buffers
;
717 if(parent
->nbuffers
== parent
->sizebuffers
)
719 bufs
= HeapReAlloc(GetProcessHeap(), 0, parent
->buffers
, sizeof(This
)*(1+parent
->nbuffers
));
721 parent
->sizebuffers
++;
723 parent
->buffers
= bufs
;
724 bufs
[parent
->nbuffers
++] = This
;
726 /* Disable until initialized.. */
727 This
->ds3dmode
= DS3DMODE_DISABLE
;
733 DS8Buffer_Destroy(This
);
737 void DS8Buffer_Destroy(DS8Buffer
*This
)
740 TRACE("Destroying %p\n", This
);
742 DS8Buffer_removenotify(This
);
744 /* Remove from list, if in list */
745 for(idx
= 0;idx
< This
->primary
->nbuffers
;++idx
)
747 if(This
->primary
->buffers
[idx
] == This
)
749 This
->primary
->buffers
[idx
] = This
->primary
->buffers
[This
->primary
->nbuffers
-1];
750 This
->primary
->nbuffers
--;
754 setALContext(This
->ctx
);
759 palSourceStop(This
->source
);
760 palSourcei(This
->source
, AL_BUFFER
, 0);
763 sources
= This
->primary
->sources
;
764 if(This
->primary
->nsources
== This
->primary
->sizesources
)
766 sources
= HeapReAlloc(GetProcessHeap(), 0, This
->primary
->sources
, sizeof(This
->source
)*(1+This
->primary
->nsources
));
768 palDeleteSources(1, &This
->source
);
770 This
->primary
->sizesources
++;
774 sources
[This
->primary
->nsources
++] = This
->source
;
775 This
->primary
->sources
= sources
;
778 HeapFree(GetProcessHeap(), 0, This
->notify
);
781 DS8Data_Release(This
->buffer
);
783 HeapFree(GetProcessHeap(), 0, This
);
786 static inline DS8Buffer
*impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8
*iface
)
788 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundBuffer8_iface
);
791 static HRESULT WINAPI
DS8Buffer_QueryInterface(IDirectSoundBuffer8
*iface
, REFIID riid
, void **ppv
)
793 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
795 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
798 if(IsEqualIID(riid
, &IID_IUnknown
) ||
799 IsEqualIID(riid
, &IID_IDirectSoundBuffer
))
801 else if(IsEqualIID(riid
, &IID_IDirectSoundBuffer8
))
803 if(This
->primary
->parent
->is_8
)
806 else if(IsEqualIID(riid
, &IID_IDirectSound3DBuffer
))
808 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
809 *ppv
= &This
->IDirectSound3DBuffer_iface
;
811 else if(IsEqualIID(riid
, &IID_IDirectSoundNotify
))
813 if((This
->buffer
->dsbflags
&DSBCAPS_CTRLPOSITIONNOTIFY
))
814 *ppv
= &This
->IDirectSoundNotify_iface
;
816 else if(IsEqualIID(riid
, &IID_IKsPropertySet
))
817 *ppv
= &This
->IKsPropertySet_iface
;
819 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid
));
823 IUnknown_AddRef((IUnknown
*)*ppv
);
827 return E_NOINTERFACE
;
830 static ULONG WINAPI
DS8Buffer_AddRef(IDirectSoundBuffer8
*iface
)
832 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
835 InterlockedIncrement(&This
->all_ref
);
836 ret
= InterlockedIncrement(&This
->ref
);
837 TRACE("new refcount %d\n", ret
);
842 static ULONG WINAPI
DS8Buffer_Release(IDirectSoundBuffer8
*iface
)
844 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
847 ret
= InterlockedDecrement(&This
->ref
);
848 TRACE("new refcount %d\n", ret
);
849 if(InterlockedDecrement(&This
->all_ref
) == 0)
850 DS8Buffer_Destroy(This
);
855 static HRESULT WINAPI
DS8Buffer_GetCaps(IDirectSoundBuffer8
*iface
, DSBCAPS
*caps
)
857 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
859 TRACE("(%p)->(%p)\n", iface
, caps
);
861 if(!caps
|| caps
->dwSize
< sizeof(*caps
))
863 WARN("Invalid DSBCAPS (%p, %u)\n", caps
, (caps
? caps
->dwSize
: 0));
864 return DSERR_INVALIDPARAM
;
867 caps
->dwFlags
= This
->buffer
->dsbflags
;
868 caps
->dwBufferBytes
= This
->buffer
->buf_size
;
869 caps
->dwUnlockTransferRate
= 4096;
870 caps
->dwPlayCpuOverhead
= 0;
874 static HRESULT WINAPI
DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD
*playpos
, DWORD
*curpos
)
876 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
877 WAVEFORMATEX
*format
= This
->buffer
->format
;
878 UINT writecursor
, pos
;
880 TRACE("(%p)->(%p, %p)\n", iface
, playpos
, curpos
);
882 EnterCriticalSection(This
->crst
);
883 setALContext(This
->ctx
);
885 if(This
->buffer
->numsegs
> 1)
887 ALint queued
= QBUFFERS
;
888 palGetSourcei(This
->source
, AL_BUFFERS_QUEUED
, &queued
);
891 pos
= (This
->curidx
+This
->buffer
->numsegs
-queued
)%This
->buffer
->numsegs
;
892 pos
*= This
->buffer
->segsize
;
893 writecursor
= This
->curidx
* This
->buffer
->segsize
;
895 else if(This
->ExtAL
->BufferSubData
)
897 ALint rwpos
[2] = { 0, 0 };
899 palGetSourceiv(This
->source
, AL_BYTE_RW_OFFSETS_SOFT
, rwpos
);
903 writecursor
= rwpos
[1];
910 palGetSourcei(This
->source
, AL_BYTE_OFFSET
, &ofs
);
911 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &status
);
915 if(status
== AL_PLAYING
)
917 writecursor
= format
->nSamplesPerSec
/ 100;
918 writecursor
*= format
->nBlockAlign
;
922 writecursor
= (writecursor
+ pos
) % This
->buffer
->buf_size
;
924 TRACE("%p Play pos = %u, write pos = %u\n", This
, pos
, writecursor
);
925 if(pos
>= This
->buffer
->buf_size
)
927 ERR("playpos >= buf_size\n");
928 pos
%= This
->buffer
->buf_size
;
930 if(writecursor
>= This
->buffer
->buf_size
)
932 ERR("writepos >= buf_size\n");
933 writecursor
%= This
->buffer
->buf_size
;
936 if(playpos
) *playpos
= pos
;
937 if(curpos
) *curpos
= writecursor
;
940 LeaveCriticalSection(This
->crst
);
945 static HRESULT WINAPI
DS8Buffer_GetFormat(IDirectSoundBuffer8
*iface
, WAVEFORMATEX
*wfx
, DWORD allocated
, DWORD
*written
)
947 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
951 TRACE("(%p)->(%p, %u, %p)\n", iface
, wfx
, allocated
, written
);
955 WARN("Cannot report format or format size\n");
956 return DSERR_INVALIDPARAM
;
959 EnterCriticalSection(This
->crst
);
960 size
= sizeof(*This
->buffer
->format
) + This
->buffer
->format
->cbSize
;
966 hr
= DSERR_INVALIDPARAM
;
968 memcpy(wfx
, This
->buffer
->format
, size
);
970 LeaveCriticalSection(This
->crst
);
975 static HRESULT WINAPI
DS8Buffer_GetVolume(IDirectSoundBuffer8
*iface
, LONG
*vol
)
977 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
981 TRACE("(%p)->(%p)\n", iface
, vol
);
985 WARN("Invalid pointer\n");
986 return DSERR_INVALIDPARAM
;
989 EnterCriticalSection(This
->crst
);
991 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
993 WARN("Volume control not set\n");
994 hr
= DSERR_CONTROLUNAVAIL
;
998 setALContext(This
->ctx
);
999 palGetSourcef(This
->source
, AL_GAIN
, &gain
);
1003 *vol
= gain_to_mB(gain
);
1004 *vol
= min(*vol
, DSBVOLUME_MAX
);
1005 *vol
= max(*vol
, DSBVOLUME_MIN
);
1008 LeaveCriticalSection(This
->crst
);
1012 static HRESULT WINAPI
DS8Buffer_GetPan(IDirectSoundBuffer8
*iface
, LONG
*pan
)
1014 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1018 TRACE("(%p)->(%p)\n", iface
, pan
);
1022 WARN("Invalid pointer\n");
1023 return DSERR_INVALIDPARAM
;
1026 EnterCriticalSection(This
->crst
);
1027 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1029 WARN("Volume control not set\n");
1030 hr
= DSERR_CONTROLUNAVAIL
;
1034 setALContext(This
->ctx
);
1035 palGetSourcefv(This
->source
, AL_POSITION
, pos
);
1039 *pan
= (LONG
)((pos
[0]+1.0) * (DSBPAN_RIGHT
-DSBPAN_LEFT
) / 2.0 + 0.5) + DSBPAN_LEFT
;
1040 *pan
= min(*pan
, DSBPAN_RIGHT
);
1041 *pan
= max(*pan
, DSBPAN_LEFT
);
1044 LeaveCriticalSection(This
->crst
);
1048 static HRESULT WINAPI
DS8Buffer_GetFrequency(IDirectSoundBuffer8
*iface
, DWORD
*freq
)
1050 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1052 ALfloat pitch
= 1.0f
;
1054 TRACE("(%p)->(%p)\n", iface
, freq
);
1058 WARN("Invalid pointer\n");
1059 return DSERR_INVALIDPARAM
;
1062 EnterCriticalSection(This
->crst
);
1063 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1065 WARN("Volume control not set\n");
1066 hr
= DSERR_CONTROLUNAVAIL
;
1070 setALContext(This
->ctx
);
1071 palGetSourcefv(This
->source
, AL_PITCH
, &pitch
);
1075 *freq
= (DWORD
)(This
->buffer
->format
->nSamplesPerSec
* pitch
);
1078 LeaveCriticalSection(This
->crst
);
1082 static HRESULT WINAPI
DS8Buffer_GetStatus(IDirectSoundBuffer8
*iface
, DWORD
*status
)
1084 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1085 ALint state
, looping
;
1087 TRACE("(%p)->(%p)\n", iface
, status
);
1091 WARN("Invalid pointer\n");
1092 return DSERR_INVALIDPARAM
;
1095 EnterCriticalSection(This
->crst
);
1097 setALContext(This
->ctx
);
1099 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1100 looping
= This
->islooping
;
1101 if(This
->buffer
->numsegs
== 1)
1102 palGetSourcei(This
->source
, AL_LOOPING
, &looping
);
1103 else if(state
!= AL_PLAYING
)
1104 state
= This
->isplaying
? AL_PLAYING
: AL_PAUSED
;
1110 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1112 if((This
->buffer
->dsbflags
&DSBCAPS_LOCSOFTWARE
))
1113 *status
|= DSBSTATUS_LOCSOFTWARE
;
1114 else if((This
->buffer
->dsbflags
&DSBCAPS_LOCHARDWARE
))
1115 *status
|= DSBSTATUS_LOCHARDWARE
;
1117 if(state
== AL_PLAYING
)
1118 *status
|= DSBSTATUS_PLAYING
| (looping
? DSBSTATUS_LOOPING
: 0);
1120 LeaveCriticalSection(This
->crst
);
1125 static HRESULT WINAPI
DS8Buffer_Initialize(IDirectSoundBuffer8
*iface
, IDirectSound
*ds
, const DSBUFFERDESC
*desc
)
1127 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1128 HRESULT hr
= DSERR_ALREADYINITIALIZED
;
1129 DS3DBUFFER
*ds3dbuffer
= &This
->ds3dbuffer
;
1131 TRACE("(%p)->(%p, %p)\n", iface
, ds
, desc
);
1133 EnterCriticalSection(This
->crst
);
1134 setALContext(This
->ctx
);
1141 hr
= DSERR_INVALIDPARAM
;
1144 WARN("Missing DSound buffer description\n");
1147 if(!desc
->lpwfxFormat
)
1149 WARN("Missing buffer format (%p)\n", This
);
1152 if((desc
->dwFlags
&DSBCAPS_CTRL3D
) && desc
->lpwfxFormat
->nChannels
!= 1)
1154 if(This
->primary
->parent
->is_8
)
1156 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1158 WARN("Can't create multi-channel 3D buffers\n");
1161 ERR("Multi-channel 3D sounds are not spatialized\n");
1164 hr
= DS8Data_Create(&This
->buffer
, desc
, This
->primary
);
1169 DS8Data
*buf
= This
->buffer
;
1171 if(buf
->format
->wBitsPerSample
== 8)
1172 memset(buf
->data
, 0x80, buf
->buf_size
);
1174 memset(buf
->data
, 0x00, buf
->buf_size
);
1176 if(This
->ExtAL
->BufferDataStatic
)
1177 This
->ExtAL
->BufferDataStatic(buf
->buffers
[0], buf
->buf_format
,
1178 buf
->data
, buf
->buf_size
,
1179 buf
->format
->nSamplesPerSec
);
1180 else if(This
->ExtAL
->BufferSubData
)
1181 palBufferData(buf
->buffers
[0], buf
->buf_format
,
1182 buf
->data
, buf
->buf_size
,
1183 buf
->format
->nSamplesPerSec
);
1189 if(This
->primary
->nsources
)
1191 This
->source
= This
->primary
->sources
[--This
->primary
->nsources
];
1192 palSourcef(This
->source
, AL_GAIN
, 1.0f
);
1193 palSourcef(This
->source
, AL_PITCH
, 1.0f
);
1198 palGenSources(1, &This
->source
);
1199 if(palGetError() != AL_NO_ERROR
)
1206 ds3dbuffer
->dwSize
= sizeof(*ds3dbuffer
);
1207 ds3dbuffer
->vPosition
.x
= 0.0;
1208 ds3dbuffer
->vPosition
.y
= 0.0;
1209 ds3dbuffer
->vPosition
.z
= 0.0;
1210 ds3dbuffer
->vVelocity
.x
= 0.0;
1211 ds3dbuffer
->vVelocity
.y
= 0.0;
1212 ds3dbuffer
->vVelocity
.z
= 0.0;
1213 ds3dbuffer
->dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1214 ds3dbuffer
->dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1215 ds3dbuffer
->vConeOrientation
.x
= 0.0;
1216 ds3dbuffer
->vConeOrientation
.y
= 0.0;
1217 ds3dbuffer
->vConeOrientation
.z
= 1.0;
1218 ds3dbuffer
->lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1219 ds3dbuffer
->flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1220 ds3dbuffer
->flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1221 ds3dbuffer
->dwMode
= DS3DMODE_NORMAL
;
1223 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
1225 if(This
->primary
->auxslot
!= 0)
1227 palSource3i(This
->source
, AL_AUXILIARY_SEND_FILTER
, This
->primary
->auxslot
, 0, AL_FILTER_NULL
);
1231 hr
= IDirectSound3DBuffer_SetAllParameters(&This
->IDirectSound3DBuffer_iface
, ds3dbuffer
, DS3D_IMMEDIATE
);
1234 ERR("SetAllParameters failed\n");
1240 ALuint source
= This
->source
;
1242 if(This
->primary
->auxslot
!= 0)
1243 palSource3i(source
, AL_AUXILIARY_SEND_FILTER
, 0, 0, AL_FILTER_NULL
);
1245 /* Non-3D sources aren't distance attenuated */
1246 This
->ds3dmode
= DS3DMODE_DISABLE
;
1247 palSource3f(source
, AL_POSITION
, 0.0f
, 0.0f
, 0.0f
);
1248 palSource3f(source
, AL_VELOCITY
, 0.0f
, 0.0f
, 0.0f
);
1249 palSource3f(source
, AL_DIRECTION
, 0.0f
, 0.0f
, 0.0f
);
1250 palSourcef(source
, AL_CONE_OUTER_GAIN
, 1.0f
);
1251 palSourcef(source
, AL_REFERENCE_DISTANCE
, 1.0f
);
1252 palSourcef(source
, AL_MAX_DISTANCE
, 1000.0f
);
1253 palSourcef(source
, AL_ROLLOFF_FACTOR
, 0.0f
);
1254 palSourcei(source
, AL_CONE_INNER_ANGLE
, 360);
1255 palSourcei(source
, AL_CONE_OUTER_ANGLE
, 360);
1256 palSourcei(source
, AL_SOURCE_RELATIVE
, AL_TRUE
);
1262 LeaveCriticalSection(This
->crst
);
1267 static HRESULT WINAPI
DS8Buffer_Lock(IDirectSoundBuffer8
*iface
, DWORD ofs
, DWORD bytes
, void **ptr1
, DWORD
*len1
, void **ptr2
, DWORD
*len2
, DWORD flags
)
1269 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1273 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This
, ofs
, bytes
, ptr1
, len1
, ptr2
, len2
, flags
);
1275 EnterCriticalSection(This
->crst
);
1276 setALContext(This
->ctx
);
1278 if(ptr1
) *ptr1
= NULL
;
1280 if(ptr2
) *ptr2
= NULL
;
1283 hr
= DSERR_INVALIDPARAM
;
1284 if(ofs
>= This
->buffer
->buf_size
)
1286 WARN("Invalid ofs %u\n", ofs
);
1291 WARN("Invalid pointer/len %p %p\n", ptr1
, len1
);
1294 if((flags
&DSBLOCK_FROMWRITECURSOR
))
1295 DS8Buffer_GetCurrentPosition(iface
, NULL
, &ofs
);
1296 if((flags
&DSBLOCK_ENTIREBUFFER
))
1297 bytes
= This
->buffer
->buf_size
;
1298 if(bytes
> This
->buffer
->buf_size
)
1300 WARN("Invalid size %u\n", bytes
);
1304 *ptr1
= This
->buffer
->data
+ ofs
;
1305 if(ofs
+bytes
>= This
->buffer
->buf_size
)
1307 *len1
= This
->buffer
->buf_size
- ofs
;
1308 remain
= bytes
- *len1
;
1316 This
->buffer
->locked
= TRUE
;
1318 if(ptr2
&& len2
&& remain
)
1320 *ptr2
= This
->buffer
->data
;
1327 LeaveCriticalSection(This
->crst
);
1331 static HRESULT WINAPI
DS8Buffer_Play(IDirectSoundBuffer8
*iface
, DWORD res1
, DWORD prio
, DWORD flags
)
1333 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1334 ALint type
, state
= AL_STOPPED
;
1337 TRACE("%p\n", This
);
1339 EnterCriticalSection(This
->crst
);
1340 setALContext(This
->ctx
);
1342 hr
= DSERR_BUFFERLOST
;
1343 if(This
->bufferlost
)
1345 WARN("Buffer %p lost\n", This
);
1349 if((This
->buffer
->dsbflags
&DSBCAPS_LOCDEFER
))
1351 if(!(This
->buffer
->dsbflags
&(DSBCAPS_LOCHARDWARE
|DSBCAPS_LOCSOFTWARE
)))
1353 if(flags
& DSBPLAY_LOCSOFTWARE
)
1354 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1356 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1361 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This
->buffer
, prio
);
1362 hr
= DSERR_INVALIDPARAM
;
1366 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1367 if(This
->buffer
->numsegs
> 1)
1369 This
->islooping
= !!(flags
&DSBPLAY_LOOPING
);
1370 if(state
!= AL_PLAYING
&& This
->isplaying
)
1375 palGetSourcei(This
->source
, AL_SOURCE_TYPE
, &type
);
1376 palSourcei(This
->source
, AL_LOOPING
, (flags
&DSBPLAY_LOOPING
) ? AL_TRUE
: AL_FALSE
);
1377 if (flags
& DSBPLAY_LOOPING
)
1378 This
->buffer
->buggy_app_detection
= 1;
1383 if(state
== AL_PLAYING
)
1386 /* alSourceQueueBuffers will implicitly set type to streaming */
1387 if(This
->buffer
->numsegs
== 1)
1389 if(type
!= AL_STATIC
)
1390 palSourcei(This
->source
, AL_BUFFER
, This
->buffer
->buffers
[0]);
1391 palSourcePlay(This
->source
);
1393 if(palGetError() != AL_NO_ERROR
)
1395 ERR("Couldn't start source\n");
1396 This
->curidx
= (This
->buffer
->numsegs
-1+This
->curidx
)%This
->buffer
->numsegs
;
1397 palSourcei(This
->source
, AL_BUFFER
, 0);
1402 This
->isplaying
= TRUE
;
1405 DS8Buffer_addnotify(This
);
1406 DS8Buffer_starttimer(This
->primary
);
1410 LeaveCriticalSection(This
->crst
);
1414 static HRESULT WINAPI
DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8
*iface
, DWORD pos
)
1416 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1418 TRACE("%p\n", This
);
1420 EnterCriticalSection(This
->crst
);
1421 setALContext(This
->ctx
);
1422 if(pos
>= This
->buffer
->buf_size
)
1424 hr
= DSERR_INVALIDPARAM
;
1427 if(This
->buffer
->numsegs
> 1)
1429 DS8Data
*buf
= This
->buffer
;
1430 This
->curidx
= pos
/buf
->segsize
;
1431 if(This
->curidx
>= buf
->numsegs
)
1432 This
->curidx
= buf
->numsegs
- 1;
1435 palSourceStop(This
->source
);
1436 palSourcei(This
->source
, AL_BUFFER
, 0);
1441 palSourcei(This
->source
, AL_BYTE_OFFSET
, pos
);
1442 This
->lastpos
= pos
;
1447 LeaveCriticalSection(This
->crst
);
1451 static HRESULT WINAPI
DS8Buffer_SetFormat(IDirectSoundBuffer8
*iface
, const WAVEFORMATEX
*wfx
)
1453 /* This call only works on primary buffers */
1454 WARN("(%p)->(%p)\n", iface
, wfx
);
1455 return DSERR_INVALIDCALL
;
1458 static HRESULT WINAPI
DS8Buffer_SetVolume(IDirectSoundBuffer8
*iface
, LONG vol
)
1460 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1463 TRACE("(%p)->(%d)\n", iface
, vol
);
1465 if(vol
> DSBVOLUME_MAX
|| vol
< DSBVOLUME_MIN
)
1467 WARN("Invalid volume (%d)\n", vol
);
1468 return DSERR_INVALIDPARAM
;
1471 EnterCriticalSection(This
->crst
);
1472 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLVOLUME
))
1473 hr
= DSERR_CONTROLUNAVAIL
;
1476 ALfloat fvol
= mB_to_gain(vol
);
1477 setALContext(This
->ctx
);
1478 palSourcef(This
->source
, AL_GAIN
, fvol
);
1481 LeaveCriticalSection(This
->crst
);
1486 static HRESULT WINAPI
DS8Buffer_SetPan(IDirectSoundBuffer8
*iface
, LONG pan
)
1488 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1491 TRACE("(%p)->(%d)\n", iface
, pan
);
1493 if(pan
> DSBPAN_RIGHT
|| pan
< DSBPAN_LEFT
)
1495 WARN("invalid parameter: pan = %d\n", pan
);
1496 return DSERR_INVALIDPARAM
;
1499 EnterCriticalSection(This
->crst
);
1500 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLPAN
))
1501 hr
= DSERR_CONTROLUNAVAIL
;
1505 pos
[0] = (pan
-DSBPAN_LEFT
) * 2.0 / (ALfloat
)(DSBPAN_RIGHT
-DSBPAN_LEFT
) - 1.0;
1506 /* NOTE: Strict movement along the X plane can cause the sound to jump
1507 * between left and right sharply. Using a curved path helps smooth it
1509 pos
[1] = sqrt(1.0 - pos
[0]*pos
[0]);
1512 setALContext(This
->ctx
);
1513 palSourcefv(This
->source
, AL_POSITION
, pos
);
1517 if(This
->buffer
->format
->nChannels
> 1)
1518 WARN("Panning for >1 channels not supported!\n");
1519 LeaveCriticalSection(This
->crst
);
1524 static HRESULT WINAPI
DS8Buffer_SetFrequency(IDirectSoundBuffer8
*iface
, DWORD freq
)
1526 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1529 TRACE("(%p)->(%u)\n", iface
, freq
);
1531 if(freq
< DSBFREQUENCY_MIN
|| freq
> DSBFREQUENCY_MAX
)
1533 WARN("invalid parameter: freq = %d\n", freq
);
1534 return DSERR_INVALIDPARAM
;
1537 EnterCriticalSection(This
->crst
);
1538 if(!(This
->buffer
->dsbflags
&DSBCAPS_CTRLFREQUENCY
))
1539 hr
= DSERR_CONTROLUNAVAIL
;
1542 ALfloat pitch
= 1.0f
;
1543 if(freq
!= DSBFREQUENCY_ORIGINAL
)
1544 pitch
= freq
/ (ALfloat
)This
->buffer
->format
->nSamplesPerSec
;
1546 setALContext(This
->ctx
);
1547 palSourcef(This
->source
, AL_PITCH
, pitch
);
1551 LeaveCriticalSection(This
->crst
);
1555 static HRESULT WINAPI
DS8Buffer_Stop(IDirectSoundBuffer8
*iface
)
1557 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1560 TRACE("(%p)->()\n", iface
);
1562 EnterCriticalSection(This
->crst
);
1563 setALContext(This
->ctx
);
1565 palSourcePause(This
->source
);
1567 /* Mac OS X doesn't immediately report state change
1568 * if Play() is immediately called after Stop, this can be fatal,
1569 * the buffer would never be restarted
1573 palGetSourcei(This
->source
, AL_SOURCE_STATE
, &state
);
1574 if(state
!= AL_PLAYING
)
1579 /* Stopped, remove from notify list */
1583 DWORD pos
= This
->lastpos
;
1584 hr
= IDirectSoundBuffer8_GetCurrentPosition(iface
, &pos
, NULL
);
1586 ERR("Own getcurrentposition failed!\n");
1587 trigger_notifies(This
, This
->lastpos
, pos
, TRUE
);
1588 This
->lastpos
= pos
;
1589 DS8Buffer_removenotify(This
);
1592 This
->isplaying
= FALSE
;
1595 LeaveCriticalSection(This
->crst
);
1600 static HRESULT WINAPI
DS8Buffer_Unlock(IDirectSoundBuffer8
*iface
, void *ptr1
, DWORD len1
, void *ptr2
, DWORD len2
)
1602 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1603 DS8Data
*buf
= This
->buffer
;
1604 DWORD bufsize
= buf
->buf_size
;
1605 DWORD_PTR ofs1
, ofs2
;
1606 DWORD_PTR boundary
= (DWORD_PTR
)buf
->data
;
1609 TRACE("(%p)->(%p, %u, %p, %u)\n", iface
, ptr1
, len1
, ptr2
, len2
);
1611 EnterCriticalSection(This
->crst
);
1612 setALContext(This
->ctx
);
1614 This
->buffer
->locked
= 0;
1615 hr
= DSERR_INVALIDPARAM
;
1617 /* Make sure offset is between boundary and boundary + bufsize */
1618 ofs1
= (DWORD_PTR
)ptr1
;
1619 ofs2
= (DWORD_PTR
)ptr2
;
1622 if(ofs2
&& ofs2
!= boundary
)
1626 if(bufsize
-ofs1
< len1
|| len2
> ofs1
)
1635 if(This
->ExtAL
->BufferDataStatic
)
1638 if(This
->ExtAL
->BufferSubData
)
1640 WAVEFORMATEX
*format
= buf
->format
;
1642 len1
-= len1
%format
->nBlockAlign
;
1644 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr1
,
1646 len2
-= len2
%format
->nBlockAlign
;
1648 This
->ExtAL
->BufferSubData(buf
->buffers
[0], buf
->buf_format
, ptr2
,
1654 palBufferData(buf
->buffers
[0], buf
->buf_format
,
1655 buf
->data
, buf
->buf_size
,
1656 buf
->format
->nSamplesPerSec
);
1660 This
->buffer
->buggy_app_detection
= 0;
1663 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary
, bufsize
, ptr1
, len1
, ptr2
, len2
);
1664 buf
->buggy_app_detection
= buf
->buf_size
;
1667 LeaveCriticalSection(This
->crst
);
1671 static HRESULT WINAPI
DS8Buffer_Restore(IDirectSoundBuffer8
*iface
)
1673 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1676 TRACE("(%p)->()\n", iface
);
1678 EnterCriticalSection(This
->crst
);
1679 if(This
->primary
->parent
->prio_level
< DSSCL_WRITEPRIMARY
||
1680 iface
== This
->primary
->write_emu
)
1682 This
->bufferlost
= 0;
1686 hr
= DSERR_BUFFERLOST
;
1687 LeaveCriticalSection(This
->crst
);
1692 static HRESULT WINAPI
DS8Buffer_SetFX(IDirectSoundBuffer8
*iface
, DWORD fxcount
, DSEFFECTDESC
*desc
, DWORD
*rescodes
)
1694 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1697 TRACE("(%p)->(%u, %p, %p)\n", This
, fxcount
, desc
, rescodes
);
1699 if(!(This
->buffer
->dsbflags
& DSBCAPS_CTRLFX
))
1701 WARN("FX control not set\n");
1702 return DSERR_CONTROLUNAVAIL
;
1707 if(desc
|| rescodes
)
1709 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1710 return DSERR_INVALIDPARAM
;
1713 /* No effects; we can handle that */
1717 if(!desc
|| !rescodes
)
1719 WARN("NULL desc and/or result pointer specified.\n");
1720 return DSERR_INVALIDPARAM
;
1723 /* We don't (currently) handle DSound effects */
1724 for(i
= 0;i
< fxcount
;++i
)
1726 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc
[i
].guidDSFXClass
));
1727 rescodes
[i
] = DSFXR_FAILED
;
1730 return DSERR_INVALIDPARAM
;
1733 static HRESULT WINAPI
DS8Buffer_AcquireResources(IDirectSoundBuffer8
*iface
, DWORD flags
, DWORD fxcount
, DWORD
*rescodes
)
1735 DS8Buffer
*This
= impl_from_IDirectSoundBuffer8(iface
);
1737 TRACE("(%p)->(%u, %u, %p)\n", This
, flags
, fxcount
, rescodes
);
1739 /* effects aren't supported at the moment.. */
1740 if(fxcount
!= 0 || rescodes
)
1742 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1743 return DSERR_INVALIDPARAM
;
1746 EnterCriticalSection(This
->crst
);
1747 if(This
->buffer
->dsbflags
& DSBCAPS_LOCDEFER
)
1749 This
->buffer
->dsbflags
&= ~(DSBCAPS_LOCSOFTWARE
|DSBCAPS_LOCHARDWARE
);
1750 if((flags
&DSBPLAY_LOCSOFTWARE
))
1751 This
->buffer
->dsbflags
|= DSBCAPS_LOCSOFTWARE
;
1753 This
->buffer
->dsbflags
|= DSBCAPS_LOCHARDWARE
;
1755 LeaveCriticalSection(This
->crst
);
1760 static HRESULT WINAPI
DS8Buffer_GetObjectInPath(IDirectSoundBuffer8
*iface
, REFGUID guid
, DWORD idx
, REFGUID rguidiface
, void **ppv
)
1762 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface
, debugstr_guid(guid
), idx
, debugstr_guid(rguidiface
), ppv
);
1766 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl
=
1768 DS8Buffer_QueryInterface
,
1772 DS8Buffer_GetCurrentPosition
,
1773 DS8Buffer_GetFormat
,
1774 DS8Buffer_GetVolume
,
1776 DS8Buffer_GetFrequency
,
1777 DS8Buffer_GetStatus
,
1778 DS8Buffer_Initialize
,
1781 DS8Buffer_SetCurrentPosition
,
1782 DS8Buffer_SetFormat
,
1783 DS8Buffer_SetVolume
,
1785 DS8Buffer_SetFrequency
,
1790 DS8Buffer_AcquireResources
,
1791 DS8Buffer_GetObjectInPath
1794 static inline DS8Buffer
*impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer
*iface
)
1796 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSound3DBuffer_iface
);
1799 static HRESULT WINAPI
DS8Buffer3D_QueryInterface(IDirectSound3DBuffer
*iface
, REFIID riid
, void **ppv
)
1801 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1802 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
1805 static ULONG WINAPI
DS8Buffer3D_AddRef(IDirectSound3DBuffer
*iface
)
1807 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1810 InterlockedIncrement(&This
->all_ref
);
1811 ret
= InterlockedIncrement(&This
->ds3d_ref
);
1812 TRACE("new refcount %d\n", ret
);
1817 static ULONG WINAPI
DS8Buffer3D_Release(IDirectSound3DBuffer
*iface
)
1819 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1822 ret
= InterlockedDecrement(&This
->ds3d_ref
);
1823 TRACE("new refcount %d\n", ret
);
1824 if(InterlockedDecrement(&This
->all_ref
) == 0)
1825 DS8Buffer_Destroy(This
);
1830 static HRESULT WINAPI
DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer
*iface
, DS3DBUFFER
*ds3dbuffer
)
1832 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1836 TRACE("%p\n", This
);
1838 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
1840 WARN("Invalid parameters %p %u\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
1841 return DSERR_INVALIDPARAM
;
1843 ds3dbuf
.dwSize
= sizeof(ds3dbuf
);
1845 EnterCriticalSection(This
->crst
);
1846 setALContext(This
->ctx
);
1848 hr
= IDirectSound3DBuffer_GetPosition(iface
, &ds3dbuf
.vPosition
);
1850 hr
= IDirectSound3DBuffer_GetVelocity(iface
, &ds3dbuf
.vVelocity
);
1852 hr
= IDirectSound3DBuffer_GetConeAngles(iface
, &ds3dbuf
.dwInsideConeAngle
, &ds3dbuf
.dwOutsideConeAngle
);
1854 hr
= IDirectSound3DBuffer_GetConeOrientation(iface
, &ds3dbuf
.vConeOrientation
);
1856 hr
= IDirectSound3DBuffer_GetConeOutsideVolume(iface
, &ds3dbuf
.lConeOutsideVolume
);
1858 hr
= IDirectSound3DBuffer_GetMinDistance(iface
, &ds3dbuf
.flMinDistance
);
1860 hr
= IDirectSound3DBuffer_GetMaxDistance(iface
, &ds3dbuf
.flMaxDistance
);
1862 hr
= IDirectSound3DBuffer_GetMode(iface
, &ds3dbuf
.dwMode
);
1864 memcpy(ds3dbuffer
, &ds3dbuf
, sizeof(ds3dbuf
));
1867 LeaveCriticalSection(This
->crst
);
1872 static HRESULT WINAPI
DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer
*iface
, DWORD
*pdwInsideConeAngle
, DWORD
*pdwOutsideConeAngle
)
1874 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1875 ALint inangle
, outangle
;
1877 TRACE("(%p)->(%p, %p)\n", This
, pdwInsideConeAngle
, pdwOutsideConeAngle
);
1878 if(!pdwInsideConeAngle
|| !pdwOutsideConeAngle
)
1880 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle
, pdwOutsideConeAngle
);
1881 return DSERR_INVALIDPARAM
;
1884 EnterCriticalSection(This
->crst
);
1885 setALContext(This
->ctx
);
1887 palGetSourcei(This
->source
, AL_CONE_INNER_ANGLE
, &inangle
);
1888 palGetSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, &outangle
);
1890 *pdwInsideConeAngle
= inangle
;
1891 *pdwOutsideConeAngle
= outangle
;
1894 LeaveCriticalSection(This
->crst
);
1899 static HRESULT WINAPI
DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVECTOR
*orient
)
1901 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1904 TRACE("(%p)->(%p)\n", This
, orient
);
1907 WARN("Invalid pointer\n");
1908 return DSERR_INVALIDPARAM
;
1911 EnterCriticalSection(This
->crst
);
1912 setALContext(This
->ctx
);
1914 palGetSourcefv(This
->source
, AL_DIRECTION
, dir
);
1918 orient
->z
= -dir
[2];
1921 LeaveCriticalSection(This
->crst
);
1926 static HRESULT WINAPI
DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG
*vol
)
1928 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1931 TRACE("(%p)->(%p)\n", This
, vol
);
1934 WARN("Invalid pointer\n");
1935 return DSERR_INVALIDPARAM
;
1938 EnterCriticalSection(This
->crst
);
1939 setALContext(This
->ctx
);
1941 palGetSourcef(This
->source
, AL_CONE_OUTER_GAIN
, &gain
);
1943 *vol
= gain_to_mB(gain
);
1944 *vol
= max(*vol
, DSBVOLUME_MIN
);
1945 *vol
= min(*vol
, DSBVOLUME_MAX
);
1948 LeaveCriticalSection(This
->crst
);
1952 static HRESULT WINAPI
DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*maxdist
)
1954 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1957 TRACE("(%p)->(%p)\n", This
, maxdist
);
1960 WARN("Invalid pointer\n");
1961 return DSERR_INVALIDPARAM
;
1964 EnterCriticalSection(This
->crst
);
1965 setALContext(This
->ctx
);
1967 palGetSourcef(This
->source
, AL_MAX_DISTANCE
, &dist
);
1972 LeaveCriticalSection(This
->crst
);
1977 static HRESULT WINAPI
DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE
*mindist
)
1979 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
1982 TRACE("(%p)->(%p)\n", This
, mindist
);
1985 WARN("Invalid pointer\n");
1986 return DSERR_INVALIDPARAM
;
1989 EnterCriticalSection(This
->crst
);
1990 setALContext(This
->ctx
);
1992 palGetSourcef(This
->source
, AL_REFERENCE_DISTANCE
, &dist
);
1997 LeaveCriticalSection(This
->crst
);
2002 static HRESULT WINAPI
DS8Buffer3D_GetMode(IDirectSound3DBuffer
*iface
, DWORD
*mode
)
2004 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2006 TRACE("(%p)->(%p)\n", This
, mode
);
2009 WARN("Invalid pointer\n");
2010 return DSERR_INVALIDPARAM
;
2013 EnterCriticalSection(This
->crst
);
2014 *mode
= This
->ds3dmode
;
2015 LeaveCriticalSection(This
->crst
);
2020 static HRESULT WINAPI
DS8Buffer3D_GetPosition(IDirectSound3DBuffer
*iface
, D3DVECTOR
*pos
)
2022 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2025 TRACE("(%p)->(%p)\n", This
, pos
);
2028 WARN("Invalid pointer\n");
2029 return DSERR_INVALIDPARAM
;
2032 EnterCriticalSection(This
->crst
);
2033 setALContext(This
->ctx
);
2035 palGetSourcefv(This
->source
, AL_POSITION
, alpos
);
2042 LeaveCriticalSection(This
->crst
);
2047 static HRESULT WINAPI
DS8Buffer3D_GetVelocity(IDirectSound3DBuffer
*iface
, D3DVECTOR
*vel
)
2049 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2052 TRACE("(%p)->(%p)\n", This
, vel
);
2055 WARN("Invalid pointer\n");
2056 return DSERR_INVALIDPARAM
;
2059 EnterCriticalSection(This
->crst
);
2060 setALContext(This
->ctx
);
2062 palGetSourcefv(This
->source
, AL_POSITION
, alvel
);
2069 LeaveCriticalSection(This
->crst
);
2074 static HRESULT WINAPI
DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer
*iface
, const DS3DBUFFER
*ds3dbuffer
, DWORD apply
)
2076 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2077 TRACE("(%p)->(%p, %u)\n", This
, ds3dbuffer
, apply
);
2079 if(!ds3dbuffer
|| ds3dbuffer
->dwSize
< sizeof(*ds3dbuffer
))
2081 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer
, ds3dbuffer
? ds3dbuffer
->dwSize
: 0);
2082 return DSERR_INVALIDPARAM
;
2085 if(ds3dbuffer
->dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2086 ds3dbuffer
->dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2088 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer
->dwInsideConeAngle
,
2089 ds3dbuffer
->dwOutsideConeAngle
);
2090 return DSERR_INVALIDPARAM
;
2093 if(ds3dbuffer
->lConeOutsideVolume
> DSBVOLUME_MAX
||
2094 ds3dbuffer
->lConeOutsideVolume
< DSBVOLUME_MIN
)
2096 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer
->lConeOutsideVolume
);
2097 return DSERR_INVALIDPARAM
;
2100 if(ds3dbuffer
->flMaxDistance
< 0.0f
)
2102 WARN("Invalid max distance (%f)\n", ds3dbuffer
->flMaxDistance
);
2103 return DSERR_INVALIDPARAM
;
2106 if(ds3dbuffer
->flMinDistance
< 0.0f
)
2108 WARN("Invalid min distance (%f)\n", ds3dbuffer
->flMinDistance
);
2109 return DSERR_INVALIDPARAM
;
2112 if(ds3dbuffer
->dwMode
!= DS3DMODE_NORMAL
&&
2113 ds3dbuffer
->dwMode
!= DS3DMODE_HEADRELATIVE
&&
2114 ds3dbuffer
->dwMode
!= DS3DMODE_DISABLE
)
2116 WARN("Invalid mode (%u)\n", ds3dbuffer
->dwMode
);
2117 return DSERR_INVALIDPARAM
;
2120 EnterCriticalSection(This
->crst
);
2121 setALContext(This
->ctx
);
2122 IDirectSound3DBuffer_SetPosition(iface
, ds3dbuffer
->vPosition
.x
, ds3dbuffer
->vPosition
.y
, ds3dbuffer
->vPosition
.z
, apply
);
2123 IDirectSound3DBuffer_SetVelocity(iface
, ds3dbuffer
->vVelocity
.x
, ds3dbuffer
->vVelocity
.y
, ds3dbuffer
->vVelocity
.z
, apply
);
2124 IDirectSound3DBuffer_SetConeAngles(iface
, ds3dbuffer
->dwInsideConeAngle
, ds3dbuffer
->dwOutsideConeAngle
, apply
);
2125 IDirectSound3DBuffer_SetConeOrientation(iface
, ds3dbuffer
->vConeOrientation
.x
, ds3dbuffer
->vConeOrientation
.y
, ds3dbuffer
->vConeOrientation
.z
, apply
);
2126 IDirectSound3DBuffer_SetConeOutsideVolume(iface
, ds3dbuffer
->lConeOutsideVolume
, apply
);
2127 IDirectSound3DBuffer_SetMinDistance(iface
, ds3dbuffer
->flMinDistance
, apply
);
2128 IDirectSound3DBuffer_SetMaxDistance(iface
, ds3dbuffer
->flMaxDistance
, apply
);
2129 IDirectSound3DBuffer_SetMode(iface
, ds3dbuffer
->dwMode
, apply
);
2131 LeaveCriticalSection(This
->crst
);
2136 static HRESULT WINAPI
DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer
*iface
, DWORD dwInsideConeAngle
, DWORD dwOutsideConeAngle
, DWORD apply
)
2138 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2140 TRACE("(%p)->(%u, %u, %u)\n", This
, dwInsideConeAngle
, dwOutsideConeAngle
, apply
);
2141 if(dwInsideConeAngle
> DS3D_MAXCONEANGLE
||
2142 dwOutsideConeAngle
> DS3D_MAXCONEANGLE
)
2144 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle
, dwOutsideConeAngle
);
2145 return DSERR_INVALIDPARAM
;
2148 EnterCriticalSection(This
->crst
);
2149 if(apply
== DS3D_DEFERRED
)
2151 This
->ds3dbuffer
.dwInsideConeAngle
= dwInsideConeAngle
;
2152 This
->ds3dbuffer
.dwOutsideConeAngle
= dwOutsideConeAngle
;
2153 This
->dirty
.bit
.cone_angles
= 1;
2157 setALContext(This
->ctx
);
2158 palSourcei(This
->source
, AL_CONE_INNER_ANGLE
, dwInsideConeAngle
);
2159 palSourcei(This
->source
, AL_CONE_OUTER_ANGLE
, dwOutsideConeAngle
);
2163 LeaveCriticalSection(This
->crst
);
2168 static HRESULT WINAPI
DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2170 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2172 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2174 EnterCriticalSection(This
->crst
);
2175 if(apply
== DS3D_DEFERRED
)
2177 This
->ds3dbuffer
.vConeOrientation
.x
= x
;
2178 This
->ds3dbuffer
.vConeOrientation
.y
= y
;
2179 This
->ds3dbuffer
.vConeOrientation
.z
= z
;
2180 This
->dirty
.bit
.cone_orient
= 1;
2184 setALContext(This
->ctx
);
2185 palSource3f(This
->source
, AL_DIRECTION
, x
, y
, -z
);
2189 LeaveCriticalSection(This
->crst
);
2194 static HRESULT WINAPI
DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer
*iface
, LONG vol
, DWORD apply
)
2196 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2198 TRACE("(%p)->(%u, %u)\n", This
, vol
, apply
);
2199 if(vol
< DSBVOLUME_MIN
|| vol
> DSBVOLUME_MAX
)
2201 WARN("Invalid volume (%u)\n", vol
);
2202 return DSERR_INVALIDPARAM
;
2205 EnterCriticalSection(This
->crst
);
2206 if(apply
== DS3D_DEFERRED
)
2208 This
->ds3dbuffer
.lConeOutsideVolume
= vol
;
2209 This
->dirty
.bit
.cone_outsidevolume
= 1;
2213 setALContext(This
->ctx
);
2214 palSourcef(This
->source
, AL_CONE_OUTER_GAIN
, mB_to_gain(vol
));
2218 LeaveCriticalSection(This
->crst
);
2223 static HRESULT WINAPI
DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer
*iface
, D3DVALUE maxdist
, DWORD apply
)
2225 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2227 TRACE("(%p)->(%f, %u)\n", This
, maxdist
, apply
);
2230 WARN("Invalid max distance (%f)\n", maxdist
);
2231 return DSERR_INVALIDPARAM
;
2234 EnterCriticalSection(This
->crst
);
2235 if(apply
== DS3D_DEFERRED
)
2237 This
->ds3dbuffer
.flMaxDistance
= maxdist
;
2238 This
->dirty
.bit
.max_distance
= 1;
2242 setALContext(This
->ctx
);
2243 palSourcef(This
->source
, AL_MAX_DISTANCE
, maxdist
);
2247 LeaveCriticalSection(This
->crst
);
2252 static HRESULT WINAPI
DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer
*iface
, D3DVALUE mindist
, DWORD apply
)
2254 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2256 TRACE("(%p)->(%f, %u)\n", This
, mindist
, apply
);
2259 WARN("Invalid min distance (%f)\n", mindist
);
2260 return DSERR_INVALIDPARAM
;
2263 EnterCriticalSection(This
->crst
);
2264 if(apply
== DS3D_DEFERRED
)
2266 This
->ds3dbuffer
.flMinDistance
= mindist
;
2267 This
->dirty
.bit
.min_distance
= 1;
2271 setALContext(This
->ctx
);
2272 palSourcef(This
->source
, AL_REFERENCE_DISTANCE
, mindist
);
2276 LeaveCriticalSection(This
->crst
);
2281 static HRESULT WINAPI
DS8Buffer3D_SetMode(IDirectSound3DBuffer
*iface
, DWORD mode
, DWORD apply
)
2283 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2285 TRACE("(%p)->(%u, %u)\n", This
, mode
, apply
);
2286 if(mode
!= DS3DMODE_NORMAL
&& mode
!= DS3DMODE_HEADRELATIVE
&&
2287 mode
!= DS3DMODE_DISABLE
)
2289 WARN("Invalid mode (%u)\n", mode
);
2290 return DSERR_INVALIDPARAM
;
2293 EnterCriticalSection(This
->crst
);
2294 if(apply
== DS3D_DEFERRED
)
2296 This
->ds3dbuffer
.dwMode
= mode
;
2297 This
->dirty
.bit
.mode
= 1;
2301 setALContext(This
->ctx
);
2302 palSourcei(This
->source
, AL_SOURCE_RELATIVE
,
2303 mode
!= DS3DMODE_NORMAL
? AL_TRUE
: AL_FALSE
);
2304 palSourcef(This
->source
, AL_ROLLOFF_FACTOR
,
2305 mode
== DS3DMODE_DISABLE
? 0.0f
: This
->primary
->rollofffactor
);
2306 This
->ds3dmode
= mode
;
2310 LeaveCriticalSection(This
->crst
);
2315 static HRESULT WINAPI
DS8Buffer3D_SetPosition(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2317 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2319 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2321 EnterCriticalSection(This
->crst
);
2322 if(apply
== DS3D_DEFERRED
)
2324 This
->ds3dbuffer
.vPosition
.x
= x
;
2325 This
->ds3dbuffer
.vPosition
.y
= y
;
2326 This
->ds3dbuffer
.vPosition
.z
= z
;
2327 This
->dirty
.bit
.pos
= 1;
2331 setALContext(This
->ctx
);
2332 palSource3f(This
->source
, AL_POSITION
, x
, y
, -z
);
2336 LeaveCriticalSection(This
->crst
);
2341 static HRESULT WINAPI
DS8Buffer3D_SetVelocity(IDirectSound3DBuffer
*iface
, D3DVALUE x
, D3DVALUE y
, D3DVALUE z
, DWORD apply
)
2343 DS8Buffer
*This
= impl_from_IDirectSound3DBuffer(iface
);
2345 TRACE("(%p)->(%f, %f, %f, %u)\n", This
, x
, y
, z
, apply
);
2347 EnterCriticalSection(This
->crst
);
2348 if(apply
== DS3D_DEFERRED
)
2350 This
->ds3dbuffer
.vVelocity
.x
= x
;
2351 This
->ds3dbuffer
.vVelocity
.y
= y
;
2352 This
->ds3dbuffer
.vVelocity
.z
= z
;
2353 This
->dirty
.bit
.vel
= 1;
2357 setALContext(This
->ctx
);
2358 palSource3f(This
->source
, AL_VELOCITY
, x
, y
, -z
);
2362 LeaveCriticalSection(This
->crst
);
2367 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl
=
2369 DS8Buffer3D_QueryInterface
,
2371 DS8Buffer3D_Release
,
2372 DS8Buffer3D_GetAllParameters
,
2373 DS8Buffer3D_GetConeAngles
,
2374 DS8Buffer3D_GetConeOrientation
,
2375 DS8Buffer3D_GetConeOutsideVolume
,
2376 DS8Buffer3D_GetMaxDistance
,
2377 DS8Buffer3D_GetMinDistance
,
2378 DS8Buffer3D_GetMode
,
2379 DS8Buffer3D_GetPosition
,
2380 DS8Buffer3D_GetVelocity
,
2381 DS8Buffer3D_SetAllParameters
,
2382 DS8Buffer3D_SetConeAngles
,
2383 DS8Buffer3D_SetConeOrientation
,
2384 DS8Buffer3D_SetConeOutsideVolume
,
2385 DS8Buffer3D_SetMaxDistance
,
2386 DS8Buffer3D_SetMinDistance
,
2387 DS8Buffer3D_SetMode
,
2388 DS8Buffer3D_SetPosition
,
2389 DS8Buffer3D_SetVelocity
2392 static inline DS8Buffer
*impl_from_IDirectSoundNotify(IDirectSoundNotify
*iface
)
2394 return CONTAINING_RECORD(iface
, DS8Buffer
, IDirectSoundNotify_iface
);
2397 static HRESULT WINAPI
DS8BufferNot_QueryInterface(IDirectSoundNotify
*iface
, REFIID riid
, void **ppv
)
2399 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2400 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2403 static ULONG WINAPI
DS8BufferNot_AddRef(IDirectSoundNotify
*iface
)
2405 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2408 InterlockedIncrement(&This
->all_ref
);
2409 ret
= InterlockedIncrement(&This
->not_ref
);
2410 TRACE("new refcount %d\n", ret
);
2415 static ULONG WINAPI
DS8BufferNot_Release(IDirectSoundNotify
*iface
)
2417 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2420 ret
= InterlockedDecrement(&This
->not_ref
);
2421 TRACE("new refcount %d\n", ret
);
2422 if(InterlockedDecrement(&This
->all_ref
) == 0)
2423 DS8Buffer_Destroy(This
);
2428 static HRESULT WINAPI
DS8BufferNot_SetNotificationPositions(IDirectSoundNotify
*iface
, DWORD count
, const DSBPOSITIONNOTIFY
*notifications
)
2430 DS8Buffer
*This
= impl_from_IDirectSoundNotify(iface
);
2431 DSBPOSITIONNOTIFY
*nots
;
2435 EnterCriticalSection(This
->crst
);
2436 hr
= DSERR_INVALIDPARAM
;
2437 if (count
&& !notifications
)
2440 hr
= IDirectSoundBuffer8_GetStatus(&This
->IDirectSoundBuffer8_iface
, &state
);
2444 hr
= DSERR_INVALIDCALL
;
2445 if((state
&DSBSTATUS_PLAYING
))
2448 hr
= DSERR_INVALIDPARAM
;
2451 HeapFree(GetProcessHeap(), 0, This
->notify
);
2459 for(i
= 0;i
< count
;++i
)
2461 if(notifications
[i
].dwOffset
>= This
->buffer
->buf_size
&&
2462 notifications
[i
].dwOffset
!= (DWORD
)DSBPN_OFFSETSTOP
)
2467 nots
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(*nots
));
2470 memcpy(nots
, notifications
, count
*sizeof(*nots
));
2472 HeapFree(GetProcessHeap(), 0, This
->notify
);
2473 This
->notify
= nots
;
2474 This
->nnotify
= count
;
2480 LeaveCriticalSection(This
->crst
);
2484 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl
=
2486 DS8BufferNot_QueryInterface
,
2487 DS8BufferNot_AddRef
,
2488 DS8BufferNot_Release
,
2489 DS8BufferNot_SetNotificationPositions
2492 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2493 handled through secondary buffers. */
2494 static inline DS8Buffer
*impl_from_IKsPropertySet(IKsPropertySet
*iface
)
2496 return CONTAINING_RECORD(iface
, DS8Buffer
, IKsPropertySet_iface
);
2499 static HRESULT WINAPI
DS8BufferProp_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, void **ppv
)
2501 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2502 return IDirectSoundBuffer8_QueryInterface(&This
->IDirectSoundBuffer8_iface
, riid
, ppv
);
2505 static ULONG WINAPI
DS8BufferProp_AddRef(IKsPropertySet
*iface
)
2507 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2510 InterlockedIncrement(&This
->all_ref
);
2511 ret
= InterlockedIncrement(&This
->prop_ref
);
2512 TRACE("new refcount %d\n", ret
);
2517 static ULONG WINAPI
DS8BufferProp_Release(IKsPropertySet
*iface
)
2519 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2522 ret
= InterlockedDecrement(&This
->prop_ref
);
2523 TRACE("new refcount %d\n", ret
);
2524 if(InterlockedDecrement(&This
->all_ref
) == 0)
2525 DS8Buffer_Destroy(This
);
2530 static HRESULT WINAPI
DS8BufferProp_Get(IKsPropertySet
*iface
, REFGUID guidPropSet
,
2532 LPVOID pInstanceData
,
2533 ULONG cbInstanceData
,
2538 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2539 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2541 WARN("(%p)->(%s, %u, %p, %u, %p, %u, %p) : semi-stub!\n", iface
, debugstr_guid(guidPropSet
),
2542 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
2544 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
2546 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
2547 hr
= IKsPropertySet_Get(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2548 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
,
2552 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2557 static HRESULT WINAPI
DS8BufferProp_Set(IKsPropertySet
*iface
, REFGUID guidPropSet
,
2559 LPVOID pInstanceData
,
2560 ULONG cbInstanceData
,
2564 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2565 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2567 WARN("(%p)->(%s, %u, %p, %u, %p, %u) : semi-stub!\n", iface
, debugstr_guid(guidPropSet
),
2568 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
2570 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
2572 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
2573 hr
= IKsPropertySet_Set(&This
->primary
->IKsPropertySet_iface
, guidPropSet
,
2574 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
,
2578 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2583 static HRESULT WINAPI
DS8BufferProp_QuerySupport(IKsPropertySet
*iface
, REFGUID guidPropSet
,
2585 PULONG pTypeSupport
)
2587 DS8Buffer
*This
= impl_from_IKsPropertySet(iface
);
2588 HRESULT hr
= E_PROP_ID_UNSUPPORTED
;
2590 WARN("(%p)->(%s, %u, %p) : semi-stub!\n", iface
, debugstr_guid(guidPropSet
), dwPropID
, pTypeSupport
);
2596 if(IsEqualIID(guidPropSet
, &DSPROPSETID_EAX20_ListenerProperties
))
2598 if((This
->buffer
->dsbflags
&DSBCAPS_CTRL3D
))
2599 hr
= IKsPropertySet_QuerySupport(&This
->primary
->IKsPropertySet_iface
,
2600 guidPropSet
, dwPropID
, pTypeSupport
);
2603 FIXME("Unhandled propset: %s\n", debugstr_guid(guidPropSet
));
2608 static const IKsPropertySetVtbl DS8BufferProp_Vtbl
=
2610 DS8BufferProp_QueryInterface
,
2611 DS8BufferProp_AddRef
,
2612 DS8BufferProp_Release
,
2615 DS8BufferProp_QuerySupport
2618 #endif /*HAVE_OPENAL*/