Use a queue timer for capturing
[dsound-openal.git] / buffer.c
blobca368b64b27d5202acf7a5934561767a13050ed3
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
23 #define CONST_VTABLE
24 #include <stdarg.h>
25 #include <string.h>
27 #define INITGUID
28 #include "windows.h"
29 #include "dsound.h"
30 #include "mmsystem.h"
31 #include "ks.h"
33 #include "dsound_private.h"
35 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
37 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
39 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
40 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
42 #ifndef E_PROP_ID_UNSUPPORTED
43 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
44 #endif
46 #ifndef DS_INCOMPLETE
47 #define DS_INCOMPLETE ((HRESULT)0x08780020)
48 #endif
50 #ifndef WAVE_FORMAT_IEEE_FLOAT
51 #define WAVE_FORMAT_IEEE_FLOAT 3
52 #endif
54 /* TODO: when bufferlost is set, return from all calls except initialize with
55 * DSERR_BUFFERLOST
57 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
58 static const IDirectSoundBufferVtbl DSBuffer_Vtbl;
59 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
60 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
61 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
64 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
66 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
69 static inline DS8Buffer *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
71 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer_iface);
74 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
76 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
79 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
81 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
84 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
86 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
90 /* Should be called with critsect held and context set.. */
91 static void DS8Buffer_addnotify(DS8Buffer *buf)
93 DS8Buffer **list;
94 DWORD i;
96 list = buf->primary->notifies;
97 for(i = 0; i < buf->primary->nnotifies; ++i)
99 if(buf == list[i])
101 ERR("Buffer %p already in notification list\n", buf);
102 return;
105 if(buf->primary->nnotifies == buf->primary->sizenotifies)
107 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
108 if(!list)
109 return;
110 buf->primary->sizenotifies++;
112 list[buf->primary->nnotifies++] = buf;
113 buf->primary->notifies = list;
117 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
119 out->Format = *format;
120 out->Format.cbSize = 0;
122 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
123 !prim->SupportedExt[EXT_MCFORMATS])
125 WARN("Multi-channel not available\n");
126 return NULL;
129 if(format->wBitsPerSample == 8)
131 switch(format->nChannels)
133 case 1: return "AL_FORMAT_MONO8";
134 case 2: return "AL_FORMAT_STEREO8";
135 case 4: return "AL_FORMAT_QUAD8";
136 case 6: return "AL_FORMAT_51CHN8";
137 case 7: return "AL_FORMAT_61CHN8";
138 case 8: return "AL_FORMAT_71CHN8";
141 else if(format->wBitsPerSample == 16)
143 switch(format->nChannels)
145 case 1: return "AL_FORMAT_MONO16";
146 case 2: return "AL_FORMAT_STEREO16";
147 case 4: return "AL_FORMAT_QUAD16";
148 case 6: return "AL_FORMAT_51CHN16";
149 case 7: return "AL_FORMAT_61CHN16";
150 case 8: return "AL_FORMAT_71CHN16";
154 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
155 format->wBitsPerSample, format->nChannels);
156 return NULL;
159 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
161 out->Format = *format;
162 out->Format.cbSize = 0;
164 if(out->Format.nChannels != 1 && out->Format.nChannels != 2 &&
165 !prim->SupportedExt[EXT_MCFORMATS])
167 WARN("Multi-channel not available\n");
168 return NULL;
171 if(format->wBitsPerSample == 32 && prim->SupportedExt[EXT_FLOAT32])
173 switch(format->nChannels)
175 case 1: return "AL_FORMAT_MONO_FLOAT32";
176 case 2: return "AL_FORMAT_STEREO_FLOAT32";
177 case 4: return "AL_FORMAT_QUAD32";
178 case 6: return "AL_FORMAT_51CHN32";
179 case 7: return "AL_FORMAT_61CHN32";
180 case 8: return "AL_FORMAT_71CHN32";
184 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
185 format->wBitsPerSample, format->nChannels);
186 return NULL;
189 /* Speaker configs */
190 #define MONO SPEAKER_FRONT_CENTER
191 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
192 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
193 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
194 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
195 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
196 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
198 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out)
200 *out = *CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
201 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
203 if(!out->Samples.wValidBitsPerSample)
204 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
205 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
207 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
208 return NULL;
211 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
212 !prim->SupportedExt[EXT_MCFORMATS])
214 WARN("Multi-channel not available\n");
215 return NULL;
218 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
220 if(out->Samples.wValidBitsPerSample == 8)
222 switch(out->dwChannelMask)
224 case MONO: return "AL_FORMAT_MONO8";
225 case STEREO: return "AL_FORMAT_STEREO8";
226 case REAR: return "AL_FORMAT_REAR8";
227 case QUAD: return "AL_FORMAT_QUAD8";
228 case X5DOT1: return "AL_FORMAT_51CHN8";
229 case X6DOT1: return "AL_FORMAT_61CHN8";
230 case X7DOT1: return "AL_FORMAT_71CHN8";
233 else if(out->Samples.wValidBitsPerSample == 16)
235 switch(out->dwChannelMask)
237 case MONO: return "AL_FORMAT_MONO16";
238 case STEREO: return "AL_FORMAT_STEREO16";
239 case REAR: return "AL_FORMAT_REAR16";
240 case QUAD: return "AL_FORMAT_QUAD16";
241 case X5DOT1: return "AL_FORMAT_51CHN16";
242 case X6DOT1: return "AL_FORMAT_61CHN16";
243 case X7DOT1: return "AL_FORMAT_71CHN16";
247 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#lx)\n",
248 out->Samples.wValidBitsPerSample, out->dwChannelMask);
249 return NULL;
251 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
252 prim->SupportedExt[EXT_FLOAT32])
254 if(out->Samples.wValidBitsPerSample == 32)
256 switch(out->dwChannelMask)
258 case MONO: return "AL_FORMAT_MONO_FLOAT32";
259 case STEREO: return "AL_FORMAT_STEREO_FLOAT32";
260 case REAR: return "AL_FORMAT_REAR32";
261 case QUAD: return "AL_FORMAT_QUAD32";
262 case X5DOT1: return "AL_FORMAT_51CHN32";
263 case X6DOT1: return "AL_FORMAT_61CHN32";
264 case X7DOT1: return "AL_FORMAT_71CHN32";
267 else
269 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
270 return NULL;
273 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#lx)\n",
274 out->Samples.wValidBitsPerSample, out->dwChannelMask);
275 return NULL;
277 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
278 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
279 return NULL;
282 static void DS8Data_Release(DS8Data *This);
283 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
285 HRESULT hr = DSERR_INVALIDPARAM;
286 const WAVEFORMATEX *format;
287 const char *fmt_str = NULL;
288 DS8Data *pBuffer;
290 format = desc->lpwfxFormat;
291 TRACE("Requested buffer format:\n"
292 " FormatTag = 0x%04x\n"
293 " Channels = %d\n"
294 " SamplesPerSec = %lu\n"
295 " AvgBytesPerSec = %lu\n"
296 " BlockAlign = %d\n"
297 " BitsPerSample = %d\n",
298 format->wFormatTag, format->nChannels,
299 format->nSamplesPerSec, format->nAvgBytesPerSec,
300 format->nBlockAlign, format->wBitsPerSample);
302 if(format->nBlockAlign == 0)
304 WARN("Invalid BlockAlign specified\n");
305 return DSERR_INVALIDPARAM;
308 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
309 * will need the EAX-RAM extension. Currently, we just tell the app it
310 * gets what it wanted. */
311 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
312 if(!pBuffer)
313 return E_OUTOFMEMORY;
314 pBuffer->ref = 1;
316 pBuffer->dsbflags = desc->dwFlags;
317 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
319 WARN("Hardware and software location requested\n");
320 goto fail;
322 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
323 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
325 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
326 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
328 hr = DSERR_BUFFERTOOSMALL;
329 if(pBuffer->buf_size < DSBSIZE_MIN)
330 goto fail;
332 hr = DSERR_INVALIDPARAM;
333 if(pBuffer->buf_size > DSBSIZE_MAX)
334 goto fail;
336 if(!(pBuffer->dsbflags&DSBCAPS_STATIC))
338 pBuffer->segsize = (format->nAvgBytesPerSec+prim->refresh-1) / prim->refresh;
339 pBuffer->segsize = clampI(pBuffer->segsize, format->nBlockAlign, 2048);
340 pBuffer->segsize += format->nBlockAlign - 1;
341 pBuffer->segsize -= pBuffer->segsize%format->nBlockAlign;
344 if(format->wFormatTag == WAVE_FORMAT_PCM)
345 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format);
346 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
347 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format);
348 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
350 const WAVEFORMATEXTENSIBLE *wfe;
352 hr = DSERR_CONTROLUNAVAIL;
353 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
354 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
355 goto fail;
357 wfe = CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format);
358 TRACE("Extensible values:\n"
359 " Samples = %d\n"
360 " ChannelMask = 0x%lx\n"
361 " SubFormat = %s\n",
362 wfe->Samples.wReserved, wfe->dwChannelMask,
363 debugstr_guid(&wfe->SubFormat));
365 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format);
367 else
368 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
370 hr = DSERR_INVALIDCALL;
371 if(!fmt_str)
372 goto fail;
374 pBuffer->buf_format = alGetEnumValue(fmt_str);
375 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
376 pBuffer->buf_format == -1)
378 WARN("Could not get OpenAL format from %s\n", fmt_str);
379 goto fail;
382 hr = E_OUTOFMEMORY;
383 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
384 if(!pBuffer->data) goto fail;
386 alGenBuffers(1, &pBuffer->bid);
387 checkALError();
389 *ppv = pBuffer;
390 return S_OK;
392 fail:
393 DS8Data_Release(pBuffer);
394 return hr;
397 static void DS8Data_AddRef(DS8Data *data)
399 InterlockedIncrement(&data->ref);
402 /* This function is always called with the device lock held */
403 static void DS8Data_Release(DS8Data *This)
405 if(InterlockedDecrement(&This->ref)) return;
407 TRACE("Deleting %p\n", This);
408 if(This->bid)
410 alDeleteBuffers(1, &This->bid);
411 checkALError();
413 HeapFree(GetProcessHeap(), 0, This->data);
414 HeapFree(GetProcessHeap(), 0, This);
418 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *prim, IDirectSoundBuffer *orig)
420 DS8Buffer *This = NULL;
421 HRESULT hr;
422 DWORD i;
424 *ppv = NULL;
425 EnterCriticalSection(prim->crst);
426 for(i = 0;i < prim->NumBufferGroups;++i)
428 if(prim->BufferGroups[i].FreeBuffers)
430 int idx = CTZ64(prim->BufferGroups[i].FreeBuffers);
431 This = prim->BufferGroups[i].Buffers + idx;
432 memset(This, 0, sizeof(*This));
433 prim->BufferGroups[i].FreeBuffers &= ~(U64(1) << idx);
434 break;
437 LeaveCriticalSection(prim->crst);
438 if(!This)
440 WARN("Allocating extra DS8Buffer\n");
441 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
442 if(!This) return DSERR_OUTOFMEMORY;
445 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
446 This->IDirectSoundBuffer_iface.lpVtbl = &DSBuffer_Vtbl;
447 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
448 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
449 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
451 This->primary = prim;
452 This->ctx = prim->ctx;
453 This->ExtAL = prim->ExtAL;
454 This->crst = prim->crst;
455 This->ref = This->all_ref = 1;
457 if(orig)
459 DS8Buffer *org = impl_from_IDirectSoundBuffer(orig);
460 hr = DSERR_BUFFERLOST;
461 if(org->bufferlost)
462 goto fail;
463 DS8Data_AddRef(org->buffer);
464 This->buffer = org->buffer;
467 /* Disable until initialized.. */
468 This->ds3dmode = DS3DMODE_DISABLE;
470 *ppv = This;
471 return DS_OK;
473 fail:
474 DS8Buffer_Destroy(This);
475 return hr;
478 void DS8Buffer_Destroy(DS8Buffer *This)
480 DS8Primary *prim = This->primary;
481 DWORD i;
483 TRACE("Destroying %p\n", This);
485 EnterCriticalSection(prim->crst);
486 /* Remove from list, if in list */
487 for(i = 0;i < prim->nnotifies;++i)
489 if(This == prim->notifies[i])
491 prim->notifies[i] = prim->notifies[--prim->nnotifies];
492 break;
496 setALContext(This->ctx);
497 if(This->source)
499 alSourceStop(This->source);
500 alSourcei(This->source, AL_BUFFER, 0);
501 checkALError();
503 prim->sources[prim->parent->share->nsources++] = This->source;
504 This->source = 0;
506 if(This->stream_bids[0])
507 alDeleteBuffers(QBUFFERS, This->stream_bids);
509 if(This->buffer)
510 DS8Data_Release(This->buffer);
512 popALContext();
514 HeapFree(GetProcessHeap(), 0, This->notify);
516 for(i = 0;i < prim->NumBufferGroups;++i)
518 DWORD_PTR idx = This - prim->BufferGroups[i].Buffers;
519 if(idx < 64)
521 prim->BufferGroups[i].FreeBuffers |= U64(1) << idx;
522 This = NULL;
523 break;
526 LeaveCriticalSection(prim->crst);
528 HeapFree(GetProcessHeap(), 0, This);
532 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
534 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
536 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
538 *ppv = NULL;
539 if(IsEqualIID(riid, &IID_IUnknown))
540 *ppv = &This->IDirectSoundBuffer8_iface;
541 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer))
542 *ppv = &This->IDirectSoundBuffer_iface;
543 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
545 if(This->primary->parent->is_8)
546 *ppv = &This->IDirectSoundBuffer8_iface;
548 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
550 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
551 *ppv = &This->IDirectSound3DBuffer_iface;
553 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
555 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
556 *ppv = &This->IDirectSoundNotify_iface;
558 else if(IsEqualIID(riid, &IID_IKsPropertySet))
559 *ppv = &This->IKsPropertySet_iface;
560 else
561 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
563 if(*ppv)
565 IUnknown_AddRef((IUnknown*)*ppv);
566 return S_OK;
569 return E_NOINTERFACE;
572 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
574 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
575 LONG ret;
577 InterlockedIncrement(&This->all_ref);
578 ret = InterlockedIncrement(&This->ref);
579 TRACE("new refcount %ld\n", ret);
581 return ret;
584 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
586 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
587 LONG ret;
589 ret = InterlockedDecrement(&This->ref);
590 TRACE("new refcount %ld\n", ret);
591 if(InterlockedDecrement(&This->all_ref) == 0)
592 DS8Buffer_Destroy(This);
594 return ret;
597 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
599 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
601 TRACE("(%p)->(%p)\n", iface, caps);
603 if(!caps || caps->dwSize < sizeof(*caps))
605 WARN("Invalid DSBCAPS (%p, %lu)\n", caps, (caps ? caps->dwSize : 0));
606 return DSERR_INVALIDPARAM;
609 caps->dwFlags = This->buffer->dsbflags;
610 caps->dwBufferBytes = This->buffer->buf_size;
611 caps->dwUnlockTransferRate = 4096;
612 caps->dwPlayCpuOverhead = 0;
613 return S_OK;
616 HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
618 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
619 ALsizei writecursor, pos;
620 DS8Data *data;
622 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
624 data = This->buffer;
625 if(!(data->dsbflags&DSBCAPS_STATIC))
627 ALint queued = QBUFFERS;
628 ALint status = 0;
629 ALint ofs = 0;
631 EnterCriticalSection(This->crst);
633 setALContext(This->ctx);
634 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
635 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
636 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
637 checkALError();
638 popALContext();
640 if(status == AL_STOPPED)
641 pos = data->segsize*queued + This->queue_base;
642 else
643 pos = ofs + This->queue_base;
644 if(pos >= data->buf_size)
646 if(This->islooping)
647 pos %= data->buf_size;
648 else if(This->isplaying)
650 pos = data->buf_size;
651 alSourceStop(This->source);
652 alSourcei(This->source, AL_BUFFER, 0);
653 This->curidx = 0;
654 This->isplaying = FALSE;
657 if(This->isplaying)
658 writecursor = (data->segsize*QBUFFERS + pos) % data->buf_size;
659 else
660 writecursor = pos % data->buf_size;
662 LeaveCriticalSection(This->crst);
664 else
666 const WAVEFORMATEX *format = &data->format.Format;
667 ALint status = 0;
668 ALint ofs = 0;
670 setALContext(This->ctx);
671 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
672 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
673 checkALError();
674 popALContext();
676 pos = (status == AL_STOPPED) ? data->buf_size : ofs;
677 if(status == AL_PLAYING)
679 writecursor = format->nSamplesPerSec / This->primary->refresh;
680 writecursor *= format->nBlockAlign;
682 else
683 writecursor = 0;
684 writecursor = (writecursor + pos) % data->buf_size;
686 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
688 if(pos > data->buf_size)
690 ERR("playpos > buf_size\n");
691 pos %= data->buf_size;
693 if(writecursor >= data->buf_size)
695 ERR("writepos >= buf_size\n");
696 writecursor %= data->buf_size;
699 if(playpos) *playpos = pos;
700 if(curpos) *curpos = writecursor;
702 return S_OK;
705 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
707 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
708 HRESULT hr = S_OK;
709 UINT size;
711 TRACE("(%p)->(%p, %lu, %p)\n", iface, wfx, allocated, written);
713 if(!wfx && !written)
715 WARN("Cannot report format or format size\n");
716 return DSERR_INVALIDPARAM;
719 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
720 if(wfx)
722 if(allocated < size)
723 hr = DSERR_INVALIDPARAM;
724 else
725 memcpy(wfx, &This->buffer->format.Format, size);
727 if(written)
728 *written = size;
730 return hr;
733 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
735 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
736 HRESULT hr;
738 TRACE("(%p)->(%p)\n", iface, vol);
740 if(!vol)
742 WARN("Invalid pointer\n");
743 return DSERR_INVALIDPARAM;
746 hr = DSERR_CONTROLUNAVAIL;
747 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
748 WARN("Volume control not set\n");
749 else
751 ALfloat gain = 1.0f;
753 setALContext(This->ctx);
754 alGetSourcef(This->source, AL_GAIN, &gain);
755 checkALError();
756 popALContext();
758 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
759 hr = DS_OK;
762 return hr;
765 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
767 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
768 HRESULT hr;
770 TRACE("(%p)->(%p)\n", iface, pan);
772 if(!pan)
774 WARN("Invalid pointer\n");
775 return DSERR_INVALIDPARAM;
778 hr = DSERR_CONTROLUNAVAIL;
779 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
780 WARN("Panning control not set\n");
781 else
783 ALfloat pos[3];
785 setALContext(This->ctx);
786 alGetSourcefv(This->source, AL_POSITION, pos);
787 checkALError();
788 popALContext();
790 *pan = clampI((LONG)((pos[0]+0.5f) * (DSBPAN_RIGHT-DSBPAN_LEFT)) + DSBPAN_LEFT,
791 DSBPAN_LEFT, DSBPAN_RIGHT);
792 hr = DS_OK;
795 return hr;
798 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
800 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
801 HRESULT hr;
803 TRACE("(%p)->(%p)\n", iface, freq);
805 if(!freq)
807 WARN("Invalid pointer\n");
808 return DSERR_INVALIDPARAM;
811 hr = DSERR_CONTROLUNAVAIL;
812 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
813 WARN("Frequency control not set\n");
814 else
816 ALfloat pitch = 1.0f;
818 setALContext(This->ctx);
819 alGetSourcefv(This->source, AL_PITCH, &pitch);
820 checkALError();
821 popALContext();
823 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
824 hr = DS_OK;
827 return hr;
830 HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
832 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
833 ALint state, looping;
835 TRACE("(%p)->(%p)\n", iface, status);
837 if(!status)
839 WARN("Invalid pointer\n");
840 return DSERR_INVALIDPARAM;
842 *status = 0;
844 if((This->buffer->dsbflags&DSBCAPS_STATIC))
846 setALContext(This->ctx);
847 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
848 alGetSourcei(This->source, AL_LOOPING, &looping);
849 checkALError();
850 popALContext();
852 else
854 EnterCriticalSection(This->crst);
856 setALContext(This->ctx);
857 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
858 checkALError();
859 popALContext();
861 if(state != AL_PLAYING)
862 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
863 looping = This->islooping;
865 LeaveCriticalSection(This->crst);
868 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
870 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
871 *status |= DSBSTATUS_LOCSOFTWARE;
872 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
873 *status |= DSBSTATUS_LOCHARDWARE;
875 if(state == AL_PLAYING)
876 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
878 TRACE("%p status = 0x%08lx\n", This, *status);
879 return S_OK;
882 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
884 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
885 DS3DBUFFER *ds3dbuffer;
886 HRESULT hr;
888 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
890 EnterCriticalSection(This->crst);
891 setALContext(This->ctx);
893 hr = DSERR_ALREADYINITIALIZED;
894 if(This->source)
895 goto out;
897 if(!This->buffer)
899 hr = DSERR_INVALIDPARAM;
900 if(!desc)
902 WARN("Missing DSound buffer description\n");
903 goto out;
905 if(!desc->lpwfxFormat)
907 WARN("Missing buffer format (%p)\n", This);
908 goto out;
910 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
912 if(This->primary->parent->is_8)
914 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
915 * buffers */
916 WARN("Can't create multi-channel 3D buffers\n");
917 goto out;
919 ERR("Multi-channel 3D sounds are not spatialized\n");
922 hr = DS8Data_Create(&This->buffer, desc, This->primary);
923 if(FAILED(hr))
924 goto out;
925 else
927 DS8Data *buf = This->buffer;
929 if(buf->format.Format.wBitsPerSample == 8)
930 memset(buf->data, 0x80, buf->buf_size);
931 else
932 memset(buf->data, 0x00, buf->buf_size);
936 if(!(This->buffer->dsbflags&DSBCAPS_STATIC))
938 alGenBuffers(QBUFFERS, This->stream_bids);
939 checkALError();
942 hr = DSERR_GENERIC;
943 if(This->primary->parent->share->nsources)
945 This->source = This->primary->sources[--(This->primary->parent->share->nsources)];
946 alSourceRewind(This->source);
947 alSourcef(This->source, AL_GAIN, 1.0f);
948 alSourcef(This->source, AL_PITCH, 1.0f);
949 checkALError();
951 else
952 goto out;
954 ds3dbuffer = &This->params;
955 ds3dbuffer->dwSize = sizeof(This->params);
956 ds3dbuffer->vPosition.x = 0.0f;
957 ds3dbuffer->vPosition.y = 0.0f;
958 ds3dbuffer->vPosition.z = 0.0f;
959 ds3dbuffer->vVelocity.x = 0.0f;
960 ds3dbuffer->vVelocity.y = 0.0f;
961 ds3dbuffer->vVelocity.z = 0.0f;
962 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
963 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
964 ds3dbuffer->vConeOrientation.x = 0.0f;
965 ds3dbuffer->vConeOrientation.y = 0.0f;
966 ds3dbuffer->vConeOrientation.z = 1.0f;
967 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
968 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
969 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
970 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
972 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
974 if(This->primary->auxslot != 0)
976 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
977 checkALError();
980 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
981 if(FAILED(hr))
983 ERR("SetAllParameters failed\n");
984 goto out;
987 else
989 ALuint source = This->source;
991 if(This->primary->auxslot != 0)
993 /* Simple hack to make reverb affect non-3D sounds too */
994 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
995 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
998 /* Non-3D sources aren't distance attenuated */
999 This->ds3dmode = DS3DMODE_DISABLE;
1000 alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
1001 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1002 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1003 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1004 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1005 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1006 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1007 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1008 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1009 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1010 checkALError();
1012 hr = S_OK;
1014 out:
1015 popALContext();
1016 LeaveCriticalSection(This->crst);
1018 return hr;
1021 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1023 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1024 DWORD remain;
1026 TRACE("(%p)->(%lu, %lu, %p, %p, %p, %p, 0x%lx)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1028 if(!ptr1 || !len1)
1030 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1031 return DSERR_INVALIDPARAM;
1034 *ptr1 = NULL;
1035 *len1 = 0;
1036 if(ptr2) *ptr2 = NULL;
1037 if(len2) *len2 = 0;
1039 if((flags&DSBLOCK_FROMWRITECURSOR))
1040 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1041 else if(ofs >= (DWORD)This->buffer->buf_size)
1043 WARN("Invalid ofs %lu\n", ofs);
1044 return DSERR_INVALIDPARAM;
1046 if((flags&DSBLOCK_ENTIREBUFFER))
1047 bytes = This->buffer->buf_size;
1048 else if(bytes > (DWORD)This->buffer->buf_size)
1050 WARN("Invalid size %lu\n", bytes);
1051 return DSERR_INVALIDPARAM;
1054 if(InterlockedExchange(&This->buffer->locked, TRUE) == TRUE)
1056 WARN("Already locked\n");
1057 return DSERR_INVALIDPARAM;
1060 *ptr1 = This->buffer->data + ofs;
1061 if(bytes >= (DWORD)This->buffer->buf_size-ofs)
1063 *len1 = This->buffer->buf_size - ofs;
1064 remain = bytes - *len1;
1066 else
1068 *len1 = bytes;
1069 remain = 0;
1072 if(ptr2 && len2 && remain)
1074 *ptr2 = This->buffer->data;
1075 *len2 = remain;
1078 return DS_OK;
1081 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1083 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1084 ALint state = AL_STOPPED;
1085 DS8Data *data;
1086 HRESULT hr;
1088 TRACE("(%p)->(%lu, %lu, %lu)\n", iface, res1, prio, flags);
1090 EnterCriticalSection(This->crst);
1091 setALContext(This->ctx);
1093 hr = DSERR_BUFFERLOST;
1094 if(This->bufferlost)
1096 WARN("Buffer %p lost\n", This);
1097 goto out;
1100 data = This->buffer;
1101 if((data->dsbflags&DSBCAPS_LOCDEFER))
1103 if(!(data->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1105 if(flags & DSBPLAY_LOCSOFTWARE)
1106 data->dsbflags |= DSBCAPS_LOCSOFTWARE;
1107 else
1108 data->dsbflags |= DSBCAPS_LOCHARDWARE;
1111 else if(prio)
1113 ERR("Invalid priority set for non-deferred buffer %p, %lu!\n", This->buffer, prio);
1114 hr = DSERR_INVALIDPARAM;
1115 goto out;
1118 if(!(data->dsbflags&DSBCAPS_STATIC))
1120 This->islooping = !!(flags&DSBPLAY_LOOPING);
1121 if(This->isplaying) state = AL_PLAYING;
1123 else
1125 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1126 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1128 checkALError();
1130 hr = S_OK;
1131 if(state == AL_PLAYING)
1132 goto out;
1134 /* alSourceQueueBuffers will implicitly set type to streaming */
1135 if((data->dsbflags&DSBCAPS_STATIC))
1137 if(state != AL_PAUSED)
1138 alSourcei(This->source, AL_BUFFER, data->bid);
1139 alSourcePlay(This->source);
1141 else
1143 alSourceRewind(This->source);
1144 alSourcei(This->source, AL_BUFFER, 0);
1145 This->queue_base = This->data_offset % data->buf_size;
1146 This->curidx = 0;
1148 if(alGetError() != AL_NO_ERROR)
1150 ERR("Couldn't start source\n");
1151 alSourcei(This->source, AL_BUFFER, 0);
1152 checkALError();
1153 hr = DSERR_GENERIC;
1154 goto out;
1156 This->isplaying = TRUE;
1157 This->playflags = flags;
1159 if(This->nnotify)
1161 DS8Buffer_addnotify(This);
1162 DS8Primary_starttimer(This->primary);
1164 else if(!(data->dsbflags&DSBCAPS_STATIC))
1165 DS8Primary_starttimer(This->primary);
1167 out:
1168 popALContext();
1169 LeaveCriticalSection(This->crst);
1170 return hr;
1173 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1175 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1176 DS8Data *data;
1178 TRACE("(%p)->(%lu)\n", iface, pos);
1180 data = This->buffer;
1181 if(pos >= (DWORD)data->buf_size)
1182 return DSERR_INVALIDPARAM;
1184 EnterCriticalSection(This->crst);
1186 if(!(data->dsbflags&DSBCAPS_STATIC))
1188 if(This->isplaying)
1190 setALContext(This->ctx);
1191 /* Perform a flush, so the next timer update will restart at the
1192 * proper position */
1193 alSourceRewind(This->source);
1194 alSourcei(This->source, AL_BUFFER, 0);
1195 checkALError();
1196 popALContext();
1198 This->queue_base = This->data_offset = pos;
1199 This->curidx = 0;
1201 else
1203 setALContext(This->ctx);
1204 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1205 popALContext();
1207 This->lastpos = pos;
1209 LeaveCriticalSection(This->crst);
1210 return DS_OK;
1213 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1215 /* This call only works on primary buffers */
1216 WARN("(%p)->(%p)\n", iface, wfx);
1217 return DSERR_INVALIDCALL;
1220 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1222 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1223 HRESULT hr = S_OK;
1225 TRACE("(%p)->(%ld)\n", iface, vol);
1227 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1229 WARN("Invalid volume (%ld)\n", vol);
1230 return DSERR_INVALIDPARAM;
1233 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1234 hr = DSERR_CONTROLUNAVAIL;
1235 if(SUCCEEDED(hr))
1237 ALfloat fvol = mB_to_gain(vol);
1238 setALContext(This->ctx);
1239 alSourcef(This->source, AL_GAIN, fvol);
1240 popALContext();
1243 return hr;
1246 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1248 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1249 HRESULT hr = S_OK;
1251 TRACE("(%p)->(%ld)\n", iface, pan);
1253 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1255 WARN("invalid parameter: pan = %ld\n", pan);
1256 return DSERR_INVALIDPARAM;
1259 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1260 hr = DSERR_CONTROLUNAVAIL;
1261 else
1263 ALfloat pos[3];
1264 pos[0] = (ALfloat)(pan-DSBPAN_LEFT)/(ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 0.5f;
1265 pos[1] = 0.0f;
1266 /* NOTE: Strict movement along the X plane can cause the sound to jump
1267 * between left and right sharply. Using a curved path helps smooth it
1268 * out */
1269 pos[2] = -sqrtf(1.0f - pos[0]*pos[0]);
1271 setALContext(This->ctx);
1272 alSourcefv(This->source, AL_POSITION, pos);
1273 checkALError();
1274 popALContext();
1276 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1277 FIXME("Panning for multi-channel buffers is not supported\n");
1280 return hr;
1283 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1285 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1286 HRESULT hr = S_OK;
1288 TRACE("(%p)->(%lu)\n", iface, freq);
1290 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1292 WARN("invalid parameter: freq = %lu\n", freq);
1293 return DSERR_INVALIDPARAM;
1296 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1297 hr = DSERR_CONTROLUNAVAIL;
1298 else
1300 ALfloat pitch = 1.0f;
1301 if(freq != DSBFREQUENCY_ORIGINAL)
1302 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1304 setALContext(This->ctx);
1305 alSourcef(This->source, AL_PITCH, pitch);
1306 checkALError();
1307 popALContext();
1310 return hr;
1313 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1315 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1317 TRACE("(%p)->()\n", iface);
1319 EnterCriticalSection(This->crst);
1320 setALContext(This->ctx);
1322 alSourcePause(This->source);
1323 checkALError();
1325 This->isplaying = FALSE;
1327 popALContext();
1328 LeaveCriticalSection(This->crst);
1330 return S_OK;
1333 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1335 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1336 DS8Data *buf = This->buffer;
1337 DWORD bufsize = buf->buf_size;
1338 DWORD_PTR ofs1, ofs2;
1339 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1340 HRESULT hr;
1342 TRACE("(%p)->(%p, %lu, %p, %lu)\n", iface, ptr1, len1, ptr2, len2);
1344 if(InterlockedExchange(&This->buffer->locked, FALSE) == FALSE)
1346 WARN("Not locked\n");
1347 return DSERR_INVALIDPARAM;
1350 hr = DSERR_INVALIDPARAM;
1351 /* Make sure offset is between boundary and boundary + bufsize */
1352 ofs1 = (DWORD_PTR)ptr1;
1353 ofs2 = (DWORD_PTR)ptr2;
1354 if(ofs1 < boundary)
1355 goto out;
1356 if(ofs2 && ofs2 != boundary)
1357 goto out;
1358 ofs1 -= boundary;
1359 ofs2 = 0;
1360 if(bufsize-ofs1 < len1 || len2 > ofs1)
1361 goto out;
1362 if(!ptr2)
1363 len2 = 0;
1365 hr = DS_OK;
1366 if(!len1 && !len2)
1367 goto out;
1369 setALContext(This->ctx);
1370 if((buf->dsbflags&DSBCAPS_STATIC))
1371 alBufferData(buf->bid, buf->buf_format, buf->data, buf->buf_size,
1372 buf->format.Format.nSamplesPerSec);
1373 checkALError();
1374 popALContext();
1376 out:
1377 if(hr != S_OK)
1378 WARN("Invalid parameters (0x%lx,%lu) (%p,%lu,%p,%lu)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1379 return hr;
1382 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1384 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1385 HRESULT hr;
1387 TRACE("(%p)->()\n", iface);
1389 EnterCriticalSection(This->crst);
1390 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1391 iface == This->primary->write_emu)
1393 This->bufferlost = 0;
1394 hr = S_OK;
1396 else
1397 hr = DSERR_BUFFERLOST;
1398 LeaveCriticalSection(This->crst);
1400 return hr;
1403 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1405 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1406 DWORD i;
1408 TRACE("(%p)->(%lu, %p, %p)\n", This, fxcount, desc, rescodes);
1410 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1412 WARN("FX control not set\n");
1413 return DSERR_CONTROLUNAVAIL;
1416 if(fxcount == 0)
1418 if(desc || rescodes)
1420 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1421 return DSERR_INVALIDPARAM;
1424 /* No effects; we can handle that */
1425 return DS_OK;
1428 if(!desc || !rescodes)
1430 WARN("NULL desc and/or result pointer specified.\n");
1431 return DSERR_INVALIDPARAM;
1434 /* We don't (currently) handle DSound effects */
1435 for(i = 0;i < fxcount;++i)
1437 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1438 rescodes[i] = DSFXR_FAILED;
1441 return DS_INCOMPLETE;
1444 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1446 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1448 TRACE("(%p)->(%lu, %lu, %p)\n", This, flags, fxcount, rescodes);
1450 /* effects aren't supported at the moment.. */
1451 if(fxcount != 0 || rescodes)
1453 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1454 return DSERR_INVALIDPARAM;
1457 EnterCriticalSection(This->crst);
1458 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1460 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1461 if((flags&DSBPLAY_LOCSOFTWARE))
1462 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1463 else
1464 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1466 LeaveCriticalSection(This->crst);
1468 return S_OK;
1471 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1473 FIXME("(%p)->(%s, %lu, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1474 return E_NOTIMPL;
1477 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl = {
1478 DS8Buffer_QueryInterface,
1479 DS8Buffer_AddRef,
1480 DS8Buffer_Release,
1481 DS8Buffer_GetCaps,
1482 DS8Buffer_GetCurrentPosition,
1483 DS8Buffer_GetFormat,
1484 DS8Buffer_GetVolume,
1485 DS8Buffer_GetPan,
1486 DS8Buffer_GetFrequency,
1487 DS8Buffer_GetStatus,
1488 DS8Buffer_Initialize,
1489 DS8Buffer_Lock,
1490 DS8Buffer_Play,
1491 DS8Buffer_SetCurrentPosition,
1492 DS8Buffer_SetFormat,
1493 DS8Buffer_SetVolume,
1494 DS8Buffer_SetPan,
1495 DS8Buffer_SetFrequency,
1496 DS8Buffer_Stop,
1497 DS8Buffer_Unlock,
1498 DS8Buffer_Restore,
1499 DS8Buffer_SetFX,
1500 DS8Buffer_AcquireResources,
1501 DS8Buffer_GetObjectInPath
1505 static HRESULT WINAPI DSBuffer_QueryInterface(IDirectSoundBuffer *iface, REFIID riid, void **ppv)
1507 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1508 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1511 static ULONG WINAPI DSBuffer_AddRef(IDirectSoundBuffer *iface)
1513 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1514 return DS8Buffer_AddRef(&This->IDirectSoundBuffer8_iface);
1517 static ULONG WINAPI DSBuffer_Release(IDirectSoundBuffer *iface)
1519 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1520 return DS8Buffer_Release(&This->IDirectSoundBuffer8_iface);
1523 static HRESULT WINAPI DSBuffer_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1525 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1526 return DS8Buffer_GetCaps(&This->IDirectSoundBuffer8_iface, caps);
1529 static HRESULT WINAPI DSBuffer_GetCurrentPosition(IDirectSoundBuffer *iface, DWORD *playpos, DWORD *curpos)
1531 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1532 return DS8Buffer_GetCurrentPosition(&This->IDirectSoundBuffer8_iface, playpos, curpos);
1535 static HRESULT WINAPI DSBuffer_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1537 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1538 return DS8Buffer_GetFormat(&This->IDirectSoundBuffer8_iface, wfx, allocated, written);
1541 static HRESULT WINAPI DSBuffer_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
1543 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1544 return DS8Buffer_GetVolume(&This->IDirectSoundBuffer8_iface, vol);
1547 static HRESULT WINAPI DSBuffer_GetPan(IDirectSoundBuffer *iface, LONG *pan)
1549 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1550 return DS8Buffer_GetPan(&This->IDirectSoundBuffer8_iface, pan);
1553 static HRESULT WINAPI DSBuffer_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
1555 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1556 return DS8Buffer_GetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1559 static HRESULT WINAPI DSBuffer_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
1561 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1562 return DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, status);
1565 static HRESULT WINAPI DSBuffer_Initialize(IDirectSoundBuffer *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1567 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1568 return DS8Buffer_Initialize(&This->IDirectSoundBuffer8_iface, ds, desc);
1571 static HRESULT WINAPI DSBuffer_Lock(IDirectSoundBuffer *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1573 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1574 return DS8Buffer_Lock(&This->IDirectSoundBuffer8_iface, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1577 static HRESULT WINAPI DSBuffer_Play(IDirectSoundBuffer *iface, DWORD res1, DWORD prio, DWORD flags)
1579 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1580 return DS8Buffer_Play(&This->IDirectSoundBuffer8_iface, res1, prio, flags);
1583 static HRESULT WINAPI DSBuffer_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD pos)
1585 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1586 return DS8Buffer_SetCurrentPosition(&This->IDirectSoundBuffer8_iface, pos);
1589 static HRESULT WINAPI DSBuffer_SetFormat(IDirectSoundBuffer *iface, const WAVEFORMATEX *wfx)
1591 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1592 return DS8Buffer_SetFormat(&This->IDirectSoundBuffer8_iface, wfx);
1595 static HRESULT WINAPI DSBuffer_SetVolume(IDirectSoundBuffer *iface, LONG vol)
1597 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1598 return DS8Buffer_SetVolume(&This->IDirectSoundBuffer8_iface, vol);
1601 static HRESULT WINAPI DSBuffer_SetPan(IDirectSoundBuffer *iface, LONG pan)
1603 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1604 return DS8Buffer_SetPan(&This->IDirectSoundBuffer8_iface, pan);
1607 static HRESULT WINAPI DSBuffer_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
1609 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1610 return DS8Buffer_SetFrequency(&This->IDirectSoundBuffer8_iface, freq);
1613 static HRESULT WINAPI DSBuffer_Stop(IDirectSoundBuffer *iface)
1615 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1616 return DS8Buffer_Stop(&This->IDirectSoundBuffer8_iface);
1619 static HRESULT WINAPI DSBuffer_Unlock(IDirectSoundBuffer *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1621 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1622 return DS8Buffer_Unlock(&This->IDirectSoundBuffer8_iface, ptr1, len1, ptr2, len2);
1625 static HRESULT WINAPI DSBuffer_Restore(IDirectSoundBuffer *iface)
1627 DS8Buffer *This = impl_from_IDirectSoundBuffer(iface);
1628 return DS8Buffer_Restore(&This->IDirectSoundBuffer8_iface);
1631 static const IDirectSoundBufferVtbl DSBuffer_Vtbl = {
1632 DSBuffer_QueryInterface,
1633 DSBuffer_AddRef,
1634 DSBuffer_Release,
1635 DSBuffer_GetCaps,
1636 DSBuffer_GetCurrentPosition,
1637 DSBuffer_GetFormat,
1638 DSBuffer_GetVolume,
1639 DSBuffer_GetPan,
1640 DSBuffer_GetFrequency,
1641 DSBuffer_GetStatus,
1642 DSBuffer_Initialize,
1643 DSBuffer_Lock,
1644 DSBuffer_Play,
1645 DSBuffer_SetCurrentPosition,
1646 DSBuffer_SetFormat,
1647 DSBuffer_SetVolume,
1648 DSBuffer_SetPan,
1649 DSBuffer_SetFrequency,
1650 DSBuffer_Stop,
1651 DSBuffer_Unlock,
1652 DSBuffer_Restore
1656 void DS8Buffer_SetParams(DS8Buffer *This, const DS3DBUFFER *params, LONG flags)
1658 const ALuint source = This->source;
1659 union BufferParamFlags dirty = { flags };
1661 if(dirty.bit.pos)
1662 alSource3f(source, AL_POSITION, params->vPosition.x, params->vPosition.y,
1663 -params->vPosition.z);
1664 if(dirty.bit.vel)
1665 alSource3f(source, AL_VELOCITY, params->vVelocity.x, params->vVelocity.y,
1666 -params->vVelocity.z);
1667 if(dirty.bit.cone_angles)
1669 alSourcei(source, AL_CONE_INNER_ANGLE, params->dwInsideConeAngle);
1670 alSourcei(source, AL_CONE_OUTER_ANGLE, params->dwOutsideConeAngle);
1672 if(dirty.bit.cone_orient)
1673 alSource3f(source, AL_DIRECTION, params->vConeOrientation.x,
1674 params->vConeOrientation.y,
1675 -params->vConeOrientation.z);
1676 if(dirty.bit.cone_outsidevolume)
1677 alSourcef(source, AL_CONE_OUTER_GAIN, mB_to_gain(params->lConeOutsideVolume));
1678 if(dirty.bit.min_distance)
1679 alSourcef(source, AL_REFERENCE_DISTANCE, params->flMinDistance);
1680 if(dirty.bit.max_distance)
1681 alSourcef(source, AL_MAX_DISTANCE, params->flMaxDistance);
1682 if(dirty.bit.mode)
1684 This->ds3dmode = params->dwMode;
1685 alSourcei(source, AL_SOURCE_RELATIVE, (params->dwMode!=DS3DMODE_NORMAL) ?
1686 AL_TRUE : AL_FALSE);
1687 alSourcef(source, AL_ROLLOFF_FACTOR, (params->dwMode==DS3DMODE_DISABLE) ?
1688 0.0f : This->primary->rollofffactor);
1692 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1694 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1695 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1698 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1700 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1701 LONG ret;
1703 InterlockedIncrement(&This->all_ref);
1704 ret = InterlockedIncrement(&This->ds3d_ref);
1705 TRACE("new refcount %ld\n", ret);
1707 return ret;
1710 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1712 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1713 LONG ret;
1715 ret = InterlockedDecrement(&This->ds3d_ref);
1716 TRACE("new refcount %ld\n", ret);
1717 if(InterlockedDecrement(&This->all_ref) == 0)
1718 DS8Buffer_Destroy(This);
1720 return ret;
1723 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
1725 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1726 ALint inangle, outangle;
1728 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
1729 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
1731 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
1732 return DSERR_INVALIDPARAM;
1735 EnterCriticalSection(This->crst);
1736 setALContext(This->ctx);
1738 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
1739 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
1740 checkALError();
1742 popALContext();
1743 LeaveCriticalSection(This->crst);
1745 *pdwInsideConeAngle = inangle;
1746 *pdwOutsideConeAngle = outangle;
1747 return S_OK;
1750 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
1752 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1753 ALfloat dir[3];
1755 TRACE("(%p)->(%p)\n", This, orient);
1756 if(!orient)
1758 WARN("Invalid pointer\n");
1759 return DSERR_INVALIDPARAM;
1762 setALContext(This->ctx);
1763 alGetSourcefv(This->source, AL_DIRECTION, dir);
1764 checkALError();
1765 popALContext();
1767 orient->x = dir[0];
1768 orient->y = dir[1];
1769 orient->z = -dir[2];
1770 return S_OK;
1773 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
1775 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1776 ALfloat gain;
1778 TRACE("(%p)->(%p)\n", This, vol);
1779 if(!vol)
1781 WARN("Invalid pointer\n");
1782 return DSERR_INVALIDPARAM;
1785 setALContext(This->ctx);
1786 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
1787 checkALError();
1788 popALContext();
1790 *vol = clampI(gain_to_mB(gain), DSBVOLUME_MIN, DSBVOLUME_MAX);
1791 return S_OK;
1794 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
1796 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1797 ALfloat dist;
1799 TRACE("(%p)->(%p)\n", This, maxdist);
1800 if(!maxdist)
1802 WARN("Invalid pointer\n");
1803 return DSERR_INVALIDPARAM;
1806 setALContext(This->ctx);
1807 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
1808 checkALError();
1809 popALContext();
1811 *maxdist = dist;
1812 return S_OK;
1815 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
1817 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1818 ALfloat dist;
1820 TRACE("(%p)->(%p)\n", This, mindist);
1821 if(!mindist)
1823 WARN("Invalid pointer\n");
1824 return DSERR_INVALIDPARAM;
1827 setALContext(This->ctx);
1828 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
1829 checkALError();
1830 popALContext();
1832 *mindist = dist;
1833 return S_OK;
1836 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
1838 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1840 TRACE("(%p)->(%p)\n", This, mode);
1841 if(!mode)
1843 WARN("Invalid pointer\n");
1844 return DSERR_INVALIDPARAM;
1847 EnterCriticalSection(This->crst);
1848 *mode = This->ds3dmode;
1849 LeaveCriticalSection(This->crst);
1851 return S_OK;
1854 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
1856 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1857 ALfloat alpos[3];
1859 TRACE("(%p)->(%p)\n", This, pos);
1860 if(!pos)
1862 WARN("Invalid pointer\n");
1863 return DSERR_INVALIDPARAM;
1866 setALContext(This->ctx);
1867 alGetSourcefv(This->source, AL_POSITION, alpos);
1868 checkALError();
1869 popALContext();
1871 pos->x = alpos[0];
1872 pos->y = alpos[1];
1873 pos->z = -alpos[2];
1874 return S_OK;
1877 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
1879 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1880 ALfloat alvel[3];
1882 TRACE("(%p)->(%p)\n", This, vel);
1883 if(!vel)
1885 WARN("Invalid pointer\n");
1886 return DSERR_INVALIDPARAM;
1889 setALContext(This->ctx);
1890 alGetSourcefv(This->source, AL_VELOCITY, alvel);
1891 checkALError();
1892 popALContext();
1894 vel->x = alvel[0];
1895 vel->y = alvel[1];
1896 vel->z = -alvel[2];
1897 return S_OK;
1900 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1902 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1904 TRACE("(%p)->(%p)\n", iface, ds3dbuffer);
1906 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1908 WARN("Invalid parameters %p %lu\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1909 return DSERR_INVALIDPARAM;
1912 EnterCriticalSection(This->crst);
1913 setALContext(This->ctx);
1915 DS8Buffer3D_GetPosition(iface, &ds3dbuffer->vPosition);
1916 DS8Buffer3D_GetVelocity(iface, &ds3dbuffer->vVelocity);
1917 DS8Buffer3D_GetConeAngles(iface, &ds3dbuffer->dwInsideConeAngle, &ds3dbuffer->dwOutsideConeAngle);
1918 DS8Buffer3D_GetConeOrientation(iface, &ds3dbuffer->vConeOrientation);
1919 DS8Buffer3D_GetConeOutsideVolume(iface, &ds3dbuffer->lConeOutsideVolume);
1920 DS8Buffer3D_GetMinDistance(iface, &ds3dbuffer->flMinDistance);
1921 DS8Buffer3D_GetMaxDistance(iface, &ds3dbuffer->flMaxDistance);
1922 DS8Buffer3D_GetMode(iface, &ds3dbuffer->dwMode);
1924 popALContext();
1925 LeaveCriticalSection(This->crst);
1927 return DS_OK;
1930 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
1932 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1934 TRACE("(%p)->(%lu, %lu, %lu)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
1935 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
1936 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
1938 WARN("Invalid cone angles (%lu, %lu)\n", dwInsideConeAngle, dwOutsideConeAngle);
1939 return DSERR_INVALIDPARAM;
1942 EnterCriticalSection(This->crst);
1943 if(apply == DS3D_DEFERRED)
1945 This->params.dwInsideConeAngle = dwInsideConeAngle;
1946 This->params.dwOutsideConeAngle = dwOutsideConeAngle;
1947 This->dirty.bit.cone_angles = 1;
1949 else
1951 setALContext(This->ctx);
1952 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
1953 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
1954 checkALError();
1955 popALContext();
1957 LeaveCriticalSection(This->crst);
1959 return S_OK;
1962 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
1964 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1966 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
1968 if(apply == DS3D_DEFERRED)
1970 EnterCriticalSection(This->crst);
1971 This->params.vConeOrientation.x = x;
1972 This->params.vConeOrientation.y = y;
1973 This->params.vConeOrientation.z = z;
1974 This->dirty.bit.cone_orient = 1;
1975 LeaveCriticalSection(This->crst);
1977 else
1979 setALContext(This->ctx);
1980 alSource3f(This->source, AL_DIRECTION, x, y, -z);
1981 checkALError();
1982 popALContext();
1985 return S_OK;
1988 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
1990 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1992 TRACE("(%p)->(%ld, %lu)\n", This, vol, apply);
1993 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
1995 WARN("Invalid volume (%ld)\n", vol);
1996 return DSERR_INVALIDPARAM;
1999 if(apply == DS3D_DEFERRED)
2001 EnterCriticalSection(This->crst);
2002 This->params.lConeOutsideVolume = vol;
2003 This->dirty.bit.cone_outsidevolume = 1;
2004 LeaveCriticalSection(This->crst);
2006 else
2008 setALContext(This->ctx);
2009 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2010 checkALError();
2011 popALContext();
2014 return S_OK;
2017 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2019 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2021 TRACE("(%p)->(%f, %lu)\n", This, maxdist, apply);
2022 if(maxdist < 0.0f)
2024 WARN("Invalid max distance (%f)\n", maxdist);
2025 return DSERR_INVALIDPARAM;
2028 if(apply == DS3D_DEFERRED)
2030 EnterCriticalSection(This->crst);
2031 This->params.flMaxDistance = maxdist;
2032 This->dirty.bit.max_distance = 1;
2033 LeaveCriticalSection(This->crst);
2035 else
2037 setALContext(This->ctx);
2038 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2039 checkALError();
2040 popALContext();
2043 return S_OK;
2046 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2048 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2050 TRACE("(%p)->(%f, %lu)\n", This, mindist, apply);
2051 if(mindist < 0.0f)
2053 WARN("Invalid min distance (%f)\n", mindist);
2054 return DSERR_INVALIDPARAM;
2057 if(apply == DS3D_DEFERRED)
2059 EnterCriticalSection(This->crst);
2060 This->params.flMinDistance = mindist;
2061 This->dirty.bit.min_distance = 1;
2062 LeaveCriticalSection(This->crst);
2064 else
2066 setALContext(This->ctx);
2067 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2068 checkALError();
2069 popALContext();
2072 return S_OK;
2075 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2077 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2079 TRACE("(%p)->(%lu, %lu)\n", This, mode, apply);
2080 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2081 mode != DS3DMODE_DISABLE)
2083 WARN("Invalid mode (%lu)\n", mode);
2084 return DSERR_INVALIDPARAM;
2087 EnterCriticalSection(This->crst);
2088 if(apply == DS3D_DEFERRED)
2090 This->params.dwMode = mode;
2091 This->dirty.bit.mode = 1;
2093 else
2095 setALContext(This->ctx);
2096 alSourcei(This->source, AL_SOURCE_RELATIVE,
2097 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2098 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2099 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2100 This->ds3dmode = mode;
2101 checkALError();
2102 popALContext();
2104 LeaveCriticalSection(This->crst);
2106 return S_OK;
2109 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2111 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2113 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2115 if(apply == DS3D_DEFERRED)
2117 EnterCriticalSection(This->crst);
2118 This->params.vPosition.x = x;
2119 This->params.vPosition.y = y;
2120 This->params.vPosition.z = z;
2121 This->dirty.bit.pos = 1;
2122 LeaveCriticalSection(This->crst);
2124 else
2126 setALContext(This->ctx);
2127 alSource3f(This->source, AL_POSITION, x, y, -z);
2128 checkALError();
2129 popALContext();
2132 return S_OK;
2135 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2137 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2139 TRACE("(%p)->(%f, %f, %f, %lu)\n", This, x, y, z, apply);
2141 if(apply == DS3D_DEFERRED)
2143 EnterCriticalSection(This->crst);
2144 This->params.vVelocity.x = x;
2145 This->params.vVelocity.y = y;
2146 This->params.vVelocity.z = z;
2147 This->dirty.bit.vel = 1;
2148 LeaveCriticalSection(This->crst);
2150 else
2152 setALContext(This->ctx);
2153 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2154 checkALError();
2155 popALContext();
2158 return S_OK;
2161 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2163 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2164 TRACE("(%p)->(%p, %lu)\n", This, ds3dbuffer, apply);
2166 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2168 WARN("Invalid DS3DBUFFER (%p, %lu)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2169 return DSERR_INVALIDPARAM;
2172 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2173 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2175 WARN("Invalid cone angles (%lu, %lu)\n",
2176 ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle);
2177 return DSERR_INVALIDPARAM;
2180 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2181 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2183 WARN("Invalid cone outside volume (%ld)\n", ds3dbuffer->lConeOutsideVolume);
2184 return DSERR_INVALIDPARAM;
2187 if(ds3dbuffer->flMaxDistance < 0.0f)
2189 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2190 return DSERR_INVALIDPARAM;
2193 if(ds3dbuffer->flMinDistance < 0.0f)
2195 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2196 return DSERR_INVALIDPARAM;
2199 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2200 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2201 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2203 WARN("Invalid mode (%lu)\n", ds3dbuffer->dwMode);
2204 return DSERR_INVALIDPARAM;
2207 if(apply == DS3D_DEFERRED)
2209 EnterCriticalSection(This->crst);
2210 This->params = *ds3dbuffer;
2211 This->params.dwSize = sizeof(This->params);
2212 This->dirty.bit.pos = 1;
2213 This->dirty.bit.vel = 1;
2214 This->dirty.bit.cone_angles = 1;
2215 This->dirty.bit.cone_orient = 1;
2216 This->dirty.bit.cone_outsidevolume = 1;
2217 This->dirty.bit.min_distance = 1;
2218 This->dirty.bit.max_distance = 1;
2219 This->dirty.bit.mode = 1;
2220 LeaveCriticalSection(This->crst);
2222 else
2224 union BufferParamFlags dirty = { 0 };
2225 dirty.bit.pos = 1;
2226 dirty.bit.vel = 1;
2227 dirty.bit.cone_angles = 1;
2228 dirty.bit.cone_orient = 1;
2229 dirty.bit.cone_outsidevolume = 1;
2230 dirty.bit.min_distance = 1;
2231 dirty.bit.max_distance = 1;
2232 dirty.bit.mode = 1;
2234 EnterCriticalSection(This->crst);
2235 setALContext(This->ctx);
2236 DS8Buffer_SetParams(This, ds3dbuffer, dirty.flags);
2237 checkALError();
2238 popALContext();
2239 LeaveCriticalSection(This->crst);
2242 return S_OK;
2245 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2247 DS8Buffer3D_QueryInterface,
2248 DS8Buffer3D_AddRef,
2249 DS8Buffer3D_Release,
2250 DS8Buffer3D_GetAllParameters,
2251 DS8Buffer3D_GetConeAngles,
2252 DS8Buffer3D_GetConeOrientation,
2253 DS8Buffer3D_GetConeOutsideVolume,
2254 DS8Buffer3D_GetMaxDistance,
2255 DS8Buffer3D_GetMinDistance,
2256 DS8Buffer3D_GetMode,
2257 DS8Buffer3D_GetPosition,
2258 DS8Buffer3D_GetVelocity,
2259 DS8Buffer3D_SetAllParameters,
2260 DS8Buffer3D_SetConeAngles,
2261 DS8Buffer3D_SetConeOrientation,
2262 DS8Buffer3D_SetConeOutsideVolume,
2263 DS8Buffer3D_SetMaxDistance,
2264 DS8Buffer3D_SetMinDistance,
2265 DS8Buffer3D_SetMode,
2266 DS8Buffer3D_SetPosition,
2267 DS8Buffer3D_SetVelocity
2271 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2273 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2274 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2277 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2279 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2280 LONG ret;
2282 InterlockedIncrement(&This->all_ref);
2283 ret = InterlockedIncrement(&This->not_ref);
2284 TRACE("new refcount %ld\n", ret);
2286 return ret;
2289 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2291 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2292 LONG ret;
2294 ret = InterlockedDecrement(&This->not_ref);
2295 TRACE("new refcount %ld\n", ret);
2296 if(InterlockedDecrement(&This->all_ref) == 0)
2297 DS8Buffer_Destroy(This);
2299 return ret;
2302 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2304 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2305 DSBPOSITIONNOTIFY *nots;
2306 DWORD state;
2307 HRESULT hr;
2309 TRACE("(%p)->(%lu, %p))\n", iface, count, notifications);
2311 EnterCriticalSection(This->crst);
2312 hr = DSERR_INVALIDPARAM;
2313 if(count && !notifications)
2314 goto out;
2316 hr = DS8Buffer_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2317 if(FAILED(hr)) goto out;
2319 hr = DSERR_INVALIDCALL;
2320 if((state&DSBSTATUS_PLAYING))
2321 goto out;
2323 if(!count)
2325 HeapFree(GetProcessHeap(), 0, This->notify);
2326 This->notify = 0;
2327 This->nnotify = 0;
2328 hr = S_OK;
2330 else
2332 DWORD i;
2334 hr = DSERR_INVALIDPARAM;
2335 for(i = 0;i < count;++i)
2337 if(notifications[i].dwOffset >= (DWORD)This->buffer->buf_size &&
2338 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2339 goto out;
2342 hr = E_OUTOFMEMORY;
2343 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2344 if(!nots) goto out;
2345 memcpy(nots, notifications, count*sizeof(*nots));
2347 HeapFree(GetProcessHeap(), 0, This->notify);
2348 This->notify = nots;
2349 This->nnotify = count;
2351 hr = S_OK;
2354 out:
2355 LeaveCriticalSection(This->crst);
2356 return hr;
2359 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2361 DS8BufferNot_QueryInterface,
2362 DS8BufferNot_AddRef,
2363 DS8BufferNot_Release,
2364 DS8BufferNot_SetNotificationPositions
2368 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2370 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2371 return DS8Buffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2374 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2376 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2377 LONG ret;
2379 InterlockedIncrement(&This->all_ref);
2380 ret = InterlockedIncrement(&This->prop_ref);
2381 TRACE("new refcount %ld\n", ret);
2383 return ret;
2386 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2388 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2389 LONG ret;
2391 ret = InterlockedDecrement(&This->prop_ref);
2392 TRACE("new refcount %ld\n", ret);
2393 if(InterlockedDecrement(&This->all_ref) == 0)
2394 DS8Buffer_Destroy(This);
2396 return ret;
2399 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2400 handled through secondary buffers. */
2401 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2402 REFGUID guidPropSet, ULONG dwPropID,
2403 LPVOID pInstanceData, ULONG cbInstanceData,
2404 LPVOID pPropData, ULONG cbPropData,
2405 ULONG *pcbReturned)
2407 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2408 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2410 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu, %p)\n", iface, debugstr_guid(guidPropSet),
2411 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2413 if(!pcbReturned)
2414 return E_POINTER;
2415 *pcbReturned = 0;
2417 #if 0
2418 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2421 else
2422 #endif
2424 /* Not a known buffer/source property. Pass it to the listener */
2425 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2426 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2427 pcbReturned);
2430 return hr;
2433 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2434 REFGUID guidPropSet, ULONG dwPropID,
2435 LPVOID pInstanceData, ULONG cbInstanceData,
2436 LPVOID pPropData, ULONG cbPropData)
2438 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2439 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2441 TRACE("(%p)->(%s, %lu, %p, %lu, %p, %lu)\n", iface, debugstr_guid(guidPropSet),
2442 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2444 #if 0
2445 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2448 else
2449 #endif
2451 /* Not a known buffer/source property. Pass it to the listener */
2452 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2453 dwPropID, pInstanceData, cbInstanceData, pPropData,
2454 cbPropData);
2457 return hr;
2460 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2461 REFGUID guidPropSet, ULONG dwPropID,
2462 ULONG *pTypeSupport)
2464 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2465 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2467 TRACE("(%p)->(%s, %lu, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2469 if(!pTypeSupport)
2470 return E_POINTER;
2471 *pTypeSupport = 0;
2473 #if 0
2474 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2477 else
2478 #endif
2480 /* Not a known buffer/source property. Pass it to the listener */
2481 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2482 guidPropSet, dwPropID, pTypeSupport);
2485 return hr;
2488 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2490 DS8BufferProp_QueryInterface,
2491 DS8BufferProp_AddRef,
2492 DS8BufferProp_Release,
2493 DS8BufferProp_Get,
2494 DS8BufferProp_Set,
2495 DS8BufferProp_QuerySupport