Fix some missing initializer warnings
[dsound-openal.git] / buffer.c
blob9a1d7194936267dcdf7489ba6c3a85ff1357c70c
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 #include <stdarg.h>
25 #ifdef __WINESRC__
27 #define COBJMACROS
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "vfwmsgs.h"
36 #include "mmsystem.h"
37 #include "winternl.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "dsound.h"
42 #include "dsound_private.h"
44 #include "ks.h"
45 #include "ksmedia.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
49 #else
51 #define WINVER 0x0600
52 #define INITGUID
53 #include <windows.h>
54 #include <dsound.h>
56 #include "dsound_private.h"
58 DEFINE_GUID(CLSID_DirectSoundPrivate,0x11ab3ec0,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
60 DEFINE_GUID(DSPROPSETID_DirectSoundDevice,0x84624f82,0x25ec,0x11d1,0xa4,0xd8,0x00,0xc0,0x4f,0xc2,0x8a,0xca);
62 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
63 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
65 #ifndef E_PROP_ID_UNSUPPORTED
66 #define E_PROP_ID_UNSUPPORTED ((HRESULT)0x80070490)
67 #endif
69 #endif
71 #ifndef WAVE_FORMAT_IEEE_FLOAT
72 #define WAVE_FORMAT_IEEE_FLOAT 3
73 #endif
75 /* TODO: when bufferlost is set, return from all calls except initialize with
76 * DSERR_BUFFERLOST
78 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl;
79 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl;
80 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl;
81 static const IKsPropertySetVtbl DS8BufferProp_Vtbl;
83 /* Amount of buffers that have to be queued when
84 * bufferdatastatic and buffersubdata are not available */
85 #define QBUFFERS 3
87 struct DS8Data
89 LONG ref;
91 /* Lock was called and unlock isn't? */
92 BOOL locked;
94 WAVEFORMATEXTENSIBLE format;
96 ALuint buf_size;
97 ALenum buf_format;
98 ALenum in_type, in_chans;
99 DWORD dsbflags;
100 BYTE *data;
101 ALuint *buffers;
102 ALuint numsegs;
103 ALuint segsize;
104 ALuint lastsegsize;
107 static void trigger_notifies(DS8Buffer *buf, DWORD lastpos, DWORD curpos, BOOL stopping)
109 DWORD i;
110 if (lastpos == curpos && !stopping)
111 return;
112 for (i = 0; i < buf->nnotify; ++i)
114 DSBPOSITIONNOTIFY *not = &buf->notify[i];
115 HANDLE event = not->hEventNotify;
116 DWORD ofs = not->dwOffset;
118 if (ofs == (DWORD)DSBPN_OFFSETSTOP)
120 if (stopping)
121 SetEvent(event);
122 continue;
125 /* Wraparound case */
126 if (curpos < lastpos)
128 if (ofs < curpos || ofs >= lastpos)
129 SetEvent(event);
130 continue;
133 /* Normal case */
134 if (ofs >= lastpos && ofs < curpos)
135 SetEvent(event);
139 static void CALLBACK DS8Buffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
140 DWORD_PTR dw1, DWORD_PTR dw2)
142 DS8Primary *prim = (DS8Primary*)dwUser;
143 DWORD i;
144 (void)timerID;
145 (void)msg;
146 (void)dw1;
147 (void)dw2;
149 EnterCriticalSection(&prim->crst);
150 setALContext(prim->ctx);
152 /* OpenAL doesn't support our lovely buffer extensions
153 * so just make sure enough buffers are queued
155 if(!prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferSubData &&
156 !prim->ExtAL.BufferDataStatic)
158 /* FIXME: Should probably use this logic to also
159 * call trigger_notifies
161 for (i = 0; i < prim->nbuffers; ++i)
163 DS8Buffer *buf = prim->buffers[i];
164 ALint done = 0, queued = QBUFFERS, state = AL_PLAYING;
165 ALuint which, ofs;
167 if (buf->buffer->numsegs == 1 || !buf->isplaying)
168 continue;
170 alGetSourcei(buf->source, AL_SOURCE_STATE, &state);
171 alGetSourcei(buf->source, AL_BUFFERS_QUEUED, &queued);
172 alGetSourcei(buf->source, AL_BUFFERS_PROCESSED, &done);
174 queued -= done;
175 while (done--)
176 alSourceUnqueueBuffers(buf->source, 1, &which);
177 while (queued < QBUFFERS)
179 which = buf->buffer->buffers[buf->curidx];
180 ofs = buf->curidx*buf->buffer->segsize;
181 if(buf->curidx < buf->buffer->numsegs-1)
182 alBufferData(which, buf->buffer->buf_format,
183 buf->buffer->data + ofs, buf->buffer->segsize,
184 buf->buffer->format.Format.nSamplesPerSec);
185 else
186 alBufferData(which, buf->buffer->buf_format,
187 buf->buffer->data + ofs, buf->buffer->lastsegsize,
188 buf->buffer->format.Format.nSamplesPerSec);
190 alSourceQueueBuffers(buf->source, 1, &which);
191 buf->curidx = (buf->curidx+1)%buf->buffer->numsegs;
192 queued++;
194 if (!buf->curidx && !buf->islooping)
196 buf->isplaying = FALSE;
197 break;
200 if (state != AL_PLAYING)
202 if (!queued)
204 IDirectSoundBuffer8_Stop(&buf->IDirectSoundBuffer8_iface);
205 continue;
207 alSourcePlay(buf->source);
209 getALError();
213 for (i = 0; i < prim->nnotifies ; )
215 DS8Buffer *buf = prim->notifies[i];
216 IDirectSoundBuffer8 *dsb = &buf->IDirectSoundBuffer8_iface;
217 DWORD status, curpos;
218 HRESULT hr;
220 hr = IDirectSoundBuffer8_GetStatus(dsb, &status);
221 if (SUCCEEDED(hr))
223 if (!(status & DSBSTATUS_PLAYING))
225 /* Stop will remove this buffer from list,
226 * and put another at the current position
227 * don't increment i
229 IDirectSoundBuffer8_Stop(dsb);
230 continue;
232 hr = IDirectSoundBuffer8_GetCurrentPosition(dsb, &curpos, NULL);
233 if (SUCCEEDED(hr))
235 trigger_notifies(buf, buf->lastpos, curpos, FALSE);
236 buf->lastpos = curpos;
239 i++;
241 popALContext();
242 LeaveCriticalSection(&prim->crst);
245 static void DS8Buffer_starttimer(DS8Primary *prim)
247 TIMECAPS time;
248 ALint refresh = FAKE_REFRESH_COUNT;
249 DWORD triggertime, res = DS_TIME_RES;
251 if(prim->timer_id)
252 return;
254 timeGetDevCaps(&time, sizeof(TIMECAPS));
256 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
257 getALCError(prim->parent->device);
259 triggertime = 1000 / refresh;
260 if(triggertime < time.wPeriodMin)
261 triggertime = time.wPeriodMin;
262 TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
264 if (res < time.wPeriodMin)
265 res = time.wPeriodMin;
266 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
267 WARN("Could not set minimum resolution, don't expect sound\n");
269 prim->timer_res = res;
270 prim->timer_id = timeSetEvent(triggertime, res, DS8Buffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
273 /* Should be called with critsect held and context set.. */
274 static void DS8Buffer_addnotify(DS8Buffer *buf)
276 DS8Buffer **list;
277 DWORD i;
279 list = buf->primary->notifies;
280 for(i = 0; i < buf->primary->nnotifies; ++i)
282 if(buf == list[i])
284 ERR("Buffer %p already in notification list\n", buf);
285 return;
288 if(buf->primary->nnotifies == buf->primary->sizenotifies)
290 list = HeapReAlloc(GetProcessHeap(), 0, list, (buf->primary->nnotifies + 1) * sizeof(*list));
291 if(!list)
292 return;
293 buf->primary->sizenotifies++;
295 list[buf->primary->nnotifies++] = buf;
296 buf->primary->notifies = list;
299 static void DS8Buffer_removenotify(DS8Buffer *buf)
301 DWORD i;
302 for(i = 0; i < buf->primary->nnotifies; ++i)
304 if(buf == buf->primary->notifies[i])
306 buf->primary->notifies[i] =
307 buf->primary->notifies[--buf->primary->nnotifies];
308 return;
313 static const char *get_fmtstr_PCM(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
315 out->Format = *format;
316 out->Format.cbSize = 0;
318 if(format->wBitsPerSample == 8)
320 *in_type = AL_UNSIGNED_BYTE;
321 switch(format->nChannels)
323 case 1: *in_chans = AL_MONO;
324 return "AL_FORMAT_MONO8";
325 case 2: *in_chans = AL_STEREO;
326 return "AL_FORMAT_STEREO8";
327 case 4: *in_chans = AL_QUAD;
328 return "AL_FORMAT_QUAD8";
329 case 6: *in_chans = AL_5POINT1;
330 return "AL_FORMAT_51CHN8";
331 case 7: *in_chans = AL_6POINT1;
332 return "AL_FORMAT_61CHN8";
333 case 8: *in_chans = AL_7POINT1;
334 return "AL_FORMAT_71CHN8";
335 default: break;
338 else if(format->wBitsPerSample == 16)
340 *in_type = AL_SHORT;
341 switch(format->nChannels)
343 case 1: *in_chans = AL_MONO;
344 return "AL_FORMAT_MONO16";
345 case 2: *in_chans = AL_STEREO;
346 return "AL_FORMAT_STEREO16";
347 case 4: *in_chans = AL_QUAD;
348 return "AL_FORMAT_QUAD16";
349 case 6: *in_chans = AL_5POINT1;
350 return "AL_FORMAT_51CHN16";
351 case 7: *in_chans = AL_6POINT1;
352 return "AL_FORMAT_61CHN16";
353 case 8: *in_chans = AL_7POINT1;
354 return "AL_FORMAT_71CHN16";
355 default: break;
358 #if 0 /* Will cause incorrect byte offsets */
359 else if(format->wBitsPerSample == 24 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
361 *in_type = AL_BYTE3;
362 switch(format->nChannels)
364 case 1: *in_chans = AL_MONO;
365 return "AL_MONO32F";
366 case 2: *in_chans = AL_STEREO;
367 return "AL_STEREO32F";
368 case 4: *in_chans = AL_QUAD;
369 return "AL_QUAD32F";
370 case 6: *in_chans = AL_5POINT1;
371 return "AL_5POINT1_32F";
372 case 7: *in_chans = AL_6POINT1;
373 return "AL_6POINT1_32F";
374 case 8: *in_chans = AL_7POINT1;
375 return "AL_7POINT1_32F";
376 default: break;
379 #endif
380 else if(format->wBitsPerSample == 32 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
382 *in_type = AL_INT;
383 switch(format->nChannels)
385 case 1: *in_chans = AL_MONO;
386 return "AL_MONO32F";
387 case 2: *in_chans = AL_STEREO;
388 return "AL_STEREO32F";
389 case 4: *in_chans = AL_QUAD;
390 return "AL_QUAD32F";
391 case 6: *in_chans = AL_5POINT1;
392 return "AL_5POINT1_32F";
393 case 7: *in_chans = AL_6POINT1;
394 return "AL_6POINT1_32F";
395 case 8: *in_chans = AL_7POINT1;
396 return "AL_7POINT1_32F";
397 default: break;
401 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
402 format->wBitsPerSample, format->nChannels);
403 return NULL;
406 static const char *get_fmtstr_FLOAT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
408 out->Format = *format;
409 out->Format.cbSize = 0;
411 if(format->wBitsPerSample == 32 &&
412 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
414 *in_type = AL_FLOAT;
415 switch(format->nChannels)
417 case 1: *in_chans = AL_MONO;
418 return "AL_FORMAT_MONO_FLOAT32";
419 case 2: *in_chans = AL_STEREO;
420 return "AL_FORMAT_STEREO_FLOAT32";
421 case 4: *in_chans = AL_QUAD;
422 return "AL_FORMAT_QUAD32";
423 case 6: *in_chans = AL_5POINT1;
424 return "AL_FORMAT_51CHN32";
425 case 7: *in_chans = AL_6POINT1;
426 return "AL_FORMAT_61CHN32";
427 case 8: *in_chans = AL_7POINT1;
428 return "AL_FORMAT_71CHN32";
429 default: break;
432 #if 0 /* Will cause incorrect byte offsets */
433 else if(format->wBitsPerSample == 64 && prim->SupportedExt[SOFT_BUFFER_SAMPLES])
435 *in_type = AL_DOUBLE;
436 switch(format->nChannels)
438 case 1: *in_chans = AL_MONO;
439 return "AL_MONO32F";
440 case 2: *in_chans = AL_STEREO;
441 return "AL_STEREO32F";
442 case 4: *in_chans = AL_QUAD;
443 return "AL_QUAD32F";
444 case 6: *in_chans = AL_5POINT1;
445 return "AL_5POINT1_32F";
446 case 7: *in_chans = AL_6POINT1;
447 return "AL_6POINT1_32F";
448 case 8: *in_chans = AL_7POINT1;
449 return "AL_7POINT1_32F";
450 default: break;
453 #endif
455 FIXME("Could not get OpenAL format (%d-bit, %d channels)\n",
456 format->wBitsPerSample, format->nChannels);
457 return NULL;
460 /* Speaker configs */
461 #define MONO SPEAKER_FRONT_CENTER
462 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
463 #define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
464 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
465 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
466 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
467 #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)
469 static const char *get_fmtstr_EXT(const DS8Primary *prim, const WAVEFORMATEX *format, WAVEFORMATEXTENSIBLE *out, ALenum *in_chans, ALenum *in_type)
471 *out = *(const WAVEFORMATEXTENSIBLE*)format;
472 out->Format.cbSize = sizeof(*out) - sizeof(out->Format);
474 if(!out->Samples.wValidBitsPerSample)
475 out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample;
476 else if(out->Samples.wValidBitsPerSample != out->Format.wBitsPerSample)
478 FIXME("Padded samples not supported (%u of %u)\n", out->Samples.wValidBitsPerSample, out->Format.wBitsPerSample);
479 return NULL;
482 if(out->dwChannelMask != MONO && out->dwChannelMask != STEREO &&
483 !prim->SupportedExt[EXT_MCFORMATS] && !prim->SupportedExt[SOFT_BUFFER_SAMPLES])
485 WARN("Multi-channel not available\n");
486 return NULL;
489 if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
491 if(out->Samples.wValidBitsPerSample == 8)
493 *in_type = AL_UNSIGNED_BYTE;
494 switch(out->dwChannelMask)
496 case MONO: *in_chans = AL_MONO;
497 return "AL_FORMAT_MONO8";
498 case STEREO: *in_chans = AL_STEREO;
499 return "AL_FORMAT_STEREO8";
500 case REAR: *in_chans = AL_REAR;
501 return "AL_FORMAT_REAR8";
502 case QUAD: *in_chans = AL_QUAD;
503 return "AL_FORMAT_QUAD8";
504 case X5DOT1: *in_chans = AL_5POINT1;
505 return "AL_FORMAT_51CHN8";
506 case X6DOT1: *in_chans = AL_6POINT1;
507 return "AL_FORMAT_61CHN8";
508 case X7DOT1: *in_chans = AL_7POINT1;
509 return "AL_FORMAT_71CHN8";
510 default: break;
513 else if(out->Samples.wValidBitsPerSample == 16)
515 *in_type = AL_SHORT;
516 switch(out->dwChannelMask)
518 case MONO: *in_chans = AL_MONO;
519 return "AL_FORMAT_MONO16";
520 case STEREO: *in_chans = AL_STEREO;
521 return "AL_FORMAT_STEREO16";
522 case REAR: *in_chans = AL_REAR;
523 return "AL_FORMAT_REAR16";
524 case QUAD: *in_chans = AL_QUAD;
525 return "AL_FORMAT_QUAD16";
526 case X5DOT1: *in_chans = AL_5POINT1;
527 return "AL_FORMAT_51CHN16";
528 case X6DOT1: *in_chans = AL_6POINT1;
529 return "AL_FORMAT_61CHN16";
530 case X7DOT1: *in_chans = AL_7POINT1;
531 return "AL_FORMAT_71CHN16";
532 default: break;
535 #if 0
536 else if(out->Samples.wValidBitsPerSample == 24 &&
537 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
539 *in_type = AL_BYTE3;
540 switch(out->dwChannelMask)
542 case MONO: *in_chans = AL_MONO;
543 return "AL_MONO32F";
544 case STEREO: *in_chans = AL_STEREO;
545 return "AL_STEREO32F";
546 case REAR: *in_chans = AL_REAR;
547 return "AL_REAR32F";
548 case QUAD: *in_chans = AL_QUAD;
549 return "AL_QUAD32F";
550 case X5DOT1: *in_chans = AL_5POINT1;
551 return "AL_5POINT1_32F";
552 case X6DOT1: *in_chans = AL_6POINT1;
553 return "AL_6POINT1_32F";
554 case X7DOT1: *in_chans = AL_7POINT1;
555 return "AL_7POINT1_32F";
556 default: break;
559 #endif
560 else if(out->Samples.wValidBitsPerSample == 32 &&
561 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
563 *in_type = AL_INT;
564 switch(out->dwChannelMask)
566 case MONO: *in_chans = AL_MONO;
567 return "AL_MONO32F";
568 case STEREO: *in_chans = AL_STEREO;
569 return "AL_STEREO32F";
570 case REAR: *in_chans = AL_REAR;
571 return "AL_REAR32F";
572 case QUAD: *in_chans = AL_QUAD;
573 return "AL_QUAD32F";
574 case X5DOT1: *in_chans = AL_5POINT1;
575 return "AL_5POINT1_32F";
576 case X6DOT1: *in_chans = AL_6POINT1;
577 return "AL_6POINT1_32F";
578 case X7DOT1: *in_chans = AL_7POINT1;
579 return "AL_7POINT1_32F";
580 default: break;
584 FIXME("Could not get OpenAL PCM format (%d-bit, channelmask %#x)\n",
585 out->Samples.wValidBitsPerSample, out->dwChannelMask);
586 return NULL;
588 else if(IsEqualGUID(&out->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
589 (prim->SupportedExt[EXT_FLOAT32] || prim->SupportedExt[SOFT_BUFFER_SAMPLES]))
591 if(out->Samples.wValidBitsPerSample == 32)
593 *in_type = AL_FLOAT;
594 switch(out->dwChannelMask)
596 case MONO: *in_chans = AL_MONO;
597 return "AL_FORMAT_MONO_FLOAT32";
598 case STEREO: *in_chans = AL_STEREO;
599 return "AL_FORMAT_STEREO_FLOAT32";
600 case REAR: *in_chans = AL_REAR;
601 return "AL_FORMAT_REAR32";
602 case QUAD: *in_chans = AL_QUAD;
603 return "AL_FORMAT_QUAD32";
604 case X5DOT1: *in_chans = AL_5POINT1;
605 return "AL_FORMAT_51CHN32";
606 case X6DOT1: *in_chans = AL_6POINT1;
607 return "AL_FORMAT_61CHN32";
608 case X7DOT1: *in_chans = AL_7POINT1;
609 return "AL_FORMAT_71CHN32";
610 default: break;
613 #if 0
614 else if(out->Samples.wValidBitsPerSample == 64 &&
615 prim->SupportedExt[SOFT_BUFFER_SAMPLES])
617 *in_type = AL_DOUBLE;
618 switch(out->dwChannelMask)
620 case MONO: *in_chans = AL_MONO;
621 return "AL_MONO32F";
622 case STEREO: *in_chans = AL_STEREO;
623 return "AL_STEREO32F";
624 case REAR: *in_chans = AL_REAR;
625 return "AL_REAR32F";
626 case QUAD: *in_chans = AL_QUAD;
627 return "AL_QUAD32F";
628 case X5DOT1: *in_chans = AL_5POINT1;
629 return "AL_5POINT1_32F";
630 case X6DOT1: *in_chans = AL_6POINT1;
631 return "AL_6POINT1_32F";
632 case X7DOT1: *in_chans = AL_7POINT1;
633 return "AL_7POINT1_32F";
634 default: break;
637 #endif
638 else
640 WARN("Invalid float bits: %u\n", out->Samples.wValidBitsPerSample);
641 return NULL;
644 FIXME("Could not get OpenAL float format (%d-bit, channelmask %#x)\n",
645 out->Samples.wValidBitsPerSample, out->dwChannelMask);
646 return NULL;
648 else if(!IsEqualGUID(&out->SubFormat, &GUID_NULL))
649 ERR("Unhandled extensible format: %s\n", debugstr_guid(&out->SubFormat));
650 return NULL;
653 static void DS8Data_Release(DS8Data *This);
654 static HRESULT DS8Data_Create(DS8Data **ppv, const DSBUFFERDESC *desc, DS8Primary *prim)
656 HRESULT hr = DSERR_INVALIDPARAM;
657 const WAVEFORMATEX *format;
658 const char *fmt_str = NULL;
659 DS8Data *pBuffer;
661 format = desc->lpwfxFormat;
662 TRACE("Requested buffer format:\n"
663 " FormatTag = 0x%04x\n"
664 " Channels = %d\n"
665 " SamplesPerSec = %u\n"
666 " AvgBytesPerSec = %u\n"
667 " BlockAlign = %d\n"
668 " BitsPerSample = %d\n",
669 format->wFormatTag, format->nChannels,
670 format->nSamplesPerSec, format->nAvgBytesPerSec,
671 format->nBlockAlign, format->wBitsPerSample);
673 if(format->nBlockAlign == 0)
675 WARN("Invalid BlockAlign specified\n");
676 return DSERR_INVALIDPARAM;
679 /* Generate a new buffer. Supporting the DSBCAPS_LOC* flags properly
680 * will need the EAX-RAM extension. Currently, we just tell the app it
681 * gets what it wanted. */
682 pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer));
683 if(!pBuffer)
684 return E_OUTOFMEMORY;
685 pBuffer->ref = 1;
687 pBuffer->dsbflags = desc->dwFlags;
688 if((pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE)) == (DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE))
690 WARN("Hardware and software location requested\n");
691 goto fail;
693 if(!(pBuffer->dsbflags&(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE|DSBCAPS_LOCDEFER)))
694 pBuffer->dsbflags |= DSBCAPS_LOCHARDWARE;
696 pBuffer->buf_size = desc->dwBufferBytes + format->nBlockAlign - 1;
697 pBuffer->buf_size -= pBuffer->buf_size%format->nBlockAlign;
699 hr = DSERR_BUFFERTOOSMALL;
700 if(pBuffer->buf_size < DSBSIZE_MIN)
701 goto fail;
703 hr = DSERR_INVALIDPARAM;
704 if(pBuffer->buf_size > DSBSIZE_MAX)
705 goto fail;
707 pBuffer->numsegs = 1;
708 pBuffer->segsize = pBuffer->buf_size;
709 pBuffer->lastsegsize = pBuffer->buf_size;
711 if(!(pBuffer->dsbflags&DSBCAPS_STATIC) && !prim->ExtAL.BufferSubData &&
712 !prim->ExtAL.BufferSamplesSOFT && !prim->ExtAL.BufferDataStatic)
714 ALCint refresh = FAKE_REFRESH_COUNT;
715 ALuint newSize;
717 alcGetIntegerv(prim->parent->device, ALC_REFRESH, 1, &refresh);
718 getALCError(prim->parent->device);
720 newSize = format->nAvgBytesPerSec/refresh + format->nBlockAlign - 1;
721 newSize -= newSize%format->nBlockAlign;
723 /* Make sure enough buffers are available */
724 if(newSize > pBuffer->buf_size/(QBUFFERS+2))
725 ERR("Buffer segments too large to stream (%u for %u)!\n",
726 newSize, pBuffer->buf_size);
727 else
729 pBuffer->numsegs = pBuffer->buf_size/newSize;
730 pBuffer->segsize = newSize;
731 pBuffer->lastsegsize = pBuffer->buf_size - (newSize*(pBuffer->numsegs-1));
732 TRACE("New streaming buffer (%u chunks, %u : %u sizes)\n",
733 pBuffer->numsegs, pBuffer->segsize, pBuffer->lastsegsize);
737 if(format->wFormatTag == WAVE_FORMAT_PCM)
738 fmt_str = get_fmtstr_PCM(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
739 else if(format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
740 fmt_str = get_fmtstr_FLOAT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
741 else if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
743 const WAVEFORMATEXTENSIBLE *wfe;
745 hr = DSERR_CONTROLUNAVAIL;
746 if(format->cbSize != sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) &&
747 format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
748 goto fail;
750 wfe = (const WAVEFORMATEXTENSIBLE*)format;
751 TRACE("Extensible values:\n"
752 " Samples = %d\n"
753 " ChannelMask = %#x\n"
754 " SubFormat = %s\n",
755 wfe->Samples.wReserved, wfe->dwChannelMask,
756 debugstr_guid(&wfe->SubFormat));
758 hr = DSERR_INVALIDCALL;
759 fmt_str = get_fmtstr_EXT(prim, format, &pBuffer->format, &pBuffer->in_chans, &pBuffer->in_type);
761 else
762 ERR("Unhandled formattag 0x%04x\n", format->wFormatTag);
764 if(!fmt_str)
765 goto fail;
767 pBuffer->buf_format = alGetEnumValue(fmt_str);
768 if(alGetError() != AL_NO_ERROR || pBuffer->buf_format == 0 ||
769 pBuffer->buf_format == -1)
771 WARN("Could not get OpenAL format from %s\n", fmt_str);
772 goto fail;
775 hr = E_OUTOFMEMORY;
776 pBuffer->buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pBuffer->buffers)*pBuffer->numsegs);
777 pBuffer->data = HeapAlloc(GetProcessHeap(), 0, pBuffer->buf_size);
778 if(!pBuffer->buffers || !pBuffer->data)
779 goto fail;
781 alGenBuffers(pBuffer->numsegs, pBuffer->buffers);
782 getALError();
784 *ppv = pBuffer;
785 return S_OK;
787 fail:
788 DS8Data_Release(pBuffer);
789 return hr;
792 static void DS8Data_AddRef(DS8Data *data)
794 InterlockedIncrement(&data->ref);
797 /* This function is always called with the device lock held */
798 static void DS8Data_Release(DS8Data *This)
800 if(InterlockedDecrement(&This->ref)) return;
802 TRACE("Deleting %p\n", This);
803 if (This->buffers && This->buffers[0])
805 alDeleteBuffers(This->numsegs, This->buffers);
806 getALError();
808 HeapFree(GetProcessHeap(), 0, This->buffers);
809 HeapFree(GetProcessHeap(), 0, This->data);
810 HeapFree(GetProcessHeap(), 0, This);
813 HRESULT DS8Buffer_Create(DS8Buffer **ppv, DS8Primary *parent, DS8Buffer *orig)
815 HRESULT hr = DSERR_OUTOFMEMORY;
816 DS8Buffer *This;
817 DS8Buffer **bufs;
819 *ppv = NULL;
820 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
821 if(!This) return hr;
823 This->primary = parent;
824 This->IDirectSoundBuffer8_iface.lpVtbl = &DS8Buffer_Vtbl;
825 This->IDirectSound3DBuffer_iface.lpVtbl = &DS8Buffer3d_Vtbl;
826 This->IDirectSoundNotify_iface.lpVtbl = &DS8BufferNot_Vtbl;
827 This->IKsPropertySet_iface.lpVtbl = &DS8BufferProp_Vtbl;
828 This->ctx = parent->ctx;
829 This->ExtAL = &parent->ExtAL;
830 This->crst = &parent->crst;
831 This->ref = This->all_ref = 1;
833 if(orig)
835 This->buffer = orig->buffer;
836 DS8Data_AddRef(This->buffer);
839 /* Append to buffer list */
840 bufs = parent->buffers;
841 if(parent->nbuffers == parent->sizebuffers)
843 bufs = HeapReAlloc(GetProcessHeap(), 0, bufs, sizeof(*bufs)*(1+parent->nbuffers));
844 if(!bufs) goto fail;
845 parent->sizebuffers++;
847 parent->buffers = bufs;
848 bufs[parent->nbuffers++] = This;
850 /* Disable until initialized.. */
851 This->ds3dmode = DS3DMODE_DISABLE;
853 *ppv = This;
854 return S_OK;
856 fail:
857 DS8Buffer_Destroy(This);
858 return hr;
861 void DS8Buffer_Destroy(DS8Buffer *This)
863 DWORD idx;
864 TRACE("Destroying %p\n", This);
866 DS8Buffer_removenotify(This);
868 /* Remove from list, if in list */
869 for(idx = 0;idx < This->primary->nbuffers;++idx)
871 if(This->primary->buffers[idx] == This)
873 This->primary->buffers[idx] = This->primary->buffers[This->primary->nbuffers-1];
874 This->primary->nbuffers--;
875 break;
878 setALContext(This->ctx);
879 if(This->source)
881 ALuint *sources;
883 alSourceStop(This->source);
884 alSourcei(This->source, AL_BUFFER, 0);
885 getALError();
887 sources = This->primary->sources;
888 if(This->primary->nsources == This->primary->sizesources)
890 sources = HeapReAlloc(GetProcessHeap(), 0, sources, sizeof(*sources)*(1+This->primary->nsources));
891 if(!sources)
892 alDeleteSources(1, &This->source);
893 else
894 This->primary->sizesources++;
896 if(sources)
898 sources[This->primary->nsources++] = This->source;
899 This->primary->sources = sources;
902 HeapFree(GetProcessHeap(), 0, This->notify);
903 This->source = 0;
904 if(This->buffer)
905 DS8Data_Release(This->buffer);
906 popALContext();
907 HeapFree(GetProcessHeap(), 0, This);
910 static inline DS8Buffer *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
912 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundBuffer8_iface);
915 static HRESULT WINAPI DS8Buffer_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid, void **ppv)
917 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
919 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
921 *ppv = NULL;
922 if(IsEqualIID(riid, &IID_IUnknown) ||
923 IsEqualIID(riid, &IID_IDirectSoundBuffer))
924 *ppv = &This->IDirectSoundBuffer8_iface;
925 else if(IsEqualIID(riid, &IID_IDirectSoundBuffer8))
927 if(This->primary->parent->is_8)
928 *ppv = &This->IDirectSoundBuffer8_iface;
930 else if(IsEqualIID(riid, &IID_IDirectSound3DBuffer))
932 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
933 *ppv = &This->IDirectSound3DBuffer_iface;
935 else if(IsEqualIID(riid, &IID_IDirectSoundNotify))
937 if((This->buffer->dsbflags&DSBCAPS_CTRLPOSITIONNOTIFY))
938 *ppv = &This->IDirectSoundNotify_iface;
940 else if(IsEqualIID(riid, &IID_IKsPropertySet))
941 *ppv = &This->IKsPropertySet_iface;
942 else
943 FIXME("Unhandled GUID: %s\n", debugstr_guid(riid));
945 if(*ppv)
947 IUnknown_AddRef((IUnknown*)*ppv);
948 return S_OK;
951 return E_NOINTERFACE;
954 static ULONG WINAPI DS8Buffer_AddRef(IDirectSoundBuffer8 *iface)
956 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
957 LONG ret;
959 InterlockedIncrement(&This->all_ref);
960 ret = InterlockedIncrement(&This->ref);
961 TRACE("new refcount %d\n", ret);
963 return ret;
966 static ULONG WINAPI DS8Buffer_Release(IDirectSoundBuffer8 *iface)
968 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
969 LONG ret;
971 ret = InterlockedDecrement(&This->ref);
972 TRACE("new refcount %d\n", ret);
973 if(InterlockedDecrement(&This->all_ref) == 0)
974 DS8Buffer_Destroy(This);
976 return ret;
979 static HRESULT WINAPI DS8Buffer_GetCaps(IDirectSoundBuffer8 *iface, DSBCAPS *caps)
981 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
983 TRACE("(%p)->(%p)\n", iface, caps);
985 if(!caps || caps->dwSize < sizeof(*caps))
987 WARN("Invalid DSBCAPS (%p, %u)\n", caps, (caps ? caps->dwSize : 0));
988 return DSERR_INVALIDPARAM;
991 caps->dwFlags = This->buffer->dsbflags;
992 caps->dwBufferBytes = This->buffer->buf_size;
993 caps->dwUnlockTransferRate = 4096;
994 caps->dwPlayCpuOverhead = 0;
995 return S_OK;
998 static HRESULT WINAPI DS8Buffer_GetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD *playpos, DWORD *curpos)
1000 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1001 WAVEFORMATEX *format = &This->buffer->format.Format;
1002 UINT writecursor, pos;
1004 TRACE("(%p)->(%p, %p)\n", iface, playpos, curpos);
1006 EnterCriticalSection(This->crst);
1007 setALContext(This->ctx);
1009 if(This->buffer->numsegs > 1)
1011 ALint queued = QBUFFERS;
1012 alGetSourcei(This->source, AL_BUFFERS_QUEUED, &queued);
1013 getALError();
1015 pos = (This->curidx+This->buffer->numsegs-queued)%This->buffer->numsegs;
1016 pos *= This->buffer->segsize;
1017 writecursor = This->curidx * This->buffer->segsize;
1019 else if(This->ExtAL->BufferSubData || This->ExtAL->BufferSamplesSOFT)
1021 ALint rwpos[2] = { 0, 0 };
1023 alGetSourceiv(This->source, AL_BYTE_RW_OFFSETS_SOFT, rwpos);
1024 getALError();
1026 pos = rwpos[0];
1027 writecursor = rwpos[1];
1029 else
1031 ALint status = 0;
1032 ALint ofs = 0;
1034 alGetSourcei(This->source, AL_BYTE_OFFSET, &ofs);
1035 alGetSourcei(This->source, AL_SOURCE_STATE, &status);
1036 getALError();
1038 pos = ofs;
1039 if(status == AL_PLAYING)
1041 writecursor = format->nSamplesPerSec / 100;
1042 writecursor *= format->nBlockAlign;
1044 else
1045 writecursor = 0;
1046 writecursor = (writecursor + pos) % This->buffer->buf_size;
1048 TRACE("%p Play pos = %u, write pos = %u\n", This, pos, writecursor);
1049 if(pos >= This->buffer->buf_size)
1051 ERR("playpos >= buf_size\n");
1052 pos %= This->buffer->buf_size;
1054 if(writecursor >= This->buffer->buf_size)
1056 ERR("writepos >= buf_size\n");
1057 writecursor %= This->buffer->buf_size;
1060 if(playpos) *playpos = pos;
1061 if(curpos) *curpos = writecursor;
1063 popALContext();
1064 LeaveCriticalSection(This->crst);
1066 return S_OK;
1069 static HRESULT WINAPI DS8Buffer_GetFormat(IDirectSoundBuffer8 *iface, WAVEFORMATEX *wfx, DWORD allocated, DWORD *written)
1071 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1072 HRESULT hr = S_OK;
1073 UINT size;
1075 TRACE("(%p)->(%p, %u, %p)\n", iface, wfx, allocated, written);
1077 if(!wfx && !written)
1079 WARN("Cannot report format or format size\n");
1080 return DSERR_INVALIDPARAM;
1083 EnterCriticalSection(This->crst);
1084 size = sizeof(This->buffer->format.Format) + This->buffer->format.Format.cbSize;
1085 if(wfx)
1087 if(allocated < size)
1088 hr = DSERR_INVALIDPARAM;
1089 else
1090 memcpy(wfx, &This->buffer->format.Format, size);
1092 if(written)
1093 *written = size;
1094 LeaveCriticalSection(This->crst);
1096 return hr;
1099 static HRESULT WINAPI DS8Buffer_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
1101 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1102 HRESULT hr;
1104 TRACE("(%p)->(%p)\n", iface, vol);
1106 if(!vol)
1108 WARN("Invalid pointer\n");
1109 return DSERR_INVALIDPARAM;
1112 EnterCriticalSection(This->crst);
1114 hr = DSERR_CONTROLUNAVAIL;
1115 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1116 WARN("Volume control not set\n");
1117 else
1119 ALfloat gain = 1.0f;
1121 setALContext(This->ctx);
1122 alGetSourcef(This->source, AL_GAIN, &gain);
1123 getALError();
1124 popALContext();
1126 *vol = gain_to_mB(gain);
1127 *vol = min(*vol, DSBVOLUME_MAX);
1128 *vol = max(*vol, DSBVOLUME_MIN);
1130 hr = DS_OK;
1133 LeaveCriticalSection(This->crst);
1134 return hr;
1137 static HRESULT WINAPI DS8Buffer_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
1139 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1140 HRESULT hr;
1142 TRACE("(%p)->(%p)\n", iface, pan);
1144 if(!pan)
1146 WARN("Invalid pointer\n");
1147 return DSERR_INVALIDPARAM;
1150 EnterCriticalSection(This->crst);
1152 hr = DSERR_CONTROLUNAVAIL;
1153 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1154 WARN("Panning control not set\n");
1155 else
1157 ALfloat pos[3];
1159 setALContext(This->ctx);
1160 alGetSourcefv(This->source, AL_POSITION, pos);
1161 getALError();
1162 popALContext();
1164 *pan = (LONG)((pos[0]+1.0) * (DSBPAN_RIGHT-DSBPAN_LEFT) / 2.0 + 0.5) + DSBPAN_LEFT;
1165 *pan = min(*pan, DSBPAN_RIGHT);
1166 *pan = max(*pan, DSBPAN_LEFT);
1168 hr = DS_OK;
1171 LeaveCriticalSection(This->crst);
1172 return hr;
1175 static HRESULT WINAPI DS8Buffer_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
1177 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1178 HRESULT hr;
1180 TRACE("(%p)->(%p)\n", iface, freq);
1182 if(!freq)
1184 WARN("Invalid pointer\n");
1185 return DSERR_INVALIDPARAM;
1188 EnterCriticalSection(This->crst);
1190 hr = DSERR_CONTROLUNAVAIL;
1191 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1192 WARN("Frequency control not set\n");
1193 else
1195 ALfloat pitch = 1.0f;
1197 setALContext(This->ctx);
1198 alGetSourcefv(This->source, AL_PITCH, &pitch);
1199 getALError();
1200 popALContext();
1202 *freq = (DWORD)(This->buffer->format.Format.nSamplesPerSec * pitch);
1204 hr = DS_OK;
1207 LeaveCriticalSection(This->crst);
1208 return hr;
1211 static HRESULT WINAPI DS8Buffer_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
1213 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1214 ALint state, looping;
1216 TRACE("(%p)->(%p)\n", iface, status);
1218 if(!status)
1220 WARN("Invalid pointer\n");
1221 return DSERR_INVALIDPARAM;
1224 EnterCriticalSection(This->crst);
1226 setALContext(This->ctx);
1227 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1228 looping = This->islooping;
1229 if(This->buffer->numsegs == 1)
1230 alGetSourcei(This->source, AL_LOOPING, &looping);
1231 else if(state != AL_PLAYING)
1232 state = This->isplaying ? AL_PLAYING : AL_PAUSED;
1233 getALError();
1234 popALContext();
1236 *status = 0;
1237 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1239 if((This->buffer->dsbflags&DSBCAPS_LOCSOFTWARE))
1240 *status |= DSBSTATUS_LOCSOFTWARE;
1241 else if((This->buffer->dsbflags&DSBCAPS_LOCHARDWARE))
1242 *status |= DSBSTATUS_LOCHARDWARE;
1244 if(state == AL_PLAYING)
1245 *status |= DSBSTATUS_PLAYING | (looping ? DSBSTATUS_LOOPING : 0);
1247 LeaveCriticalSection(This->crst);
1249 return S_OK;
1252 static HRESULT WINAPI DS8Buffer_Initialize(IDirectSoundBuffer8 *iface, IDirectSound *ds, const DSBUFFERDESC *desc)
1254 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1255 DS3DBUFFER *ds3dbuffer;
1256 HRESULT hr;
1258 TRACE("(%p)->(%p, %p)\n", iface, ds, desc);
1260 EnterCriticalSection(This->crst);
1261 setALContext(This->ctx);
1263 hr = DSERR_ALREADYINITIALIZED;
1264 if(This->source)
1265 goto out;
1267 if(!This->buffer)
1269 hr = DSERR_INVALIDPARAM;
1270 if(!desc)
1272 WARN("Missing DSound buffer description\n");
1273 goto out;
1275 if(!desc->lpwfxFormat)
1277 WARN("Missing buffer format (%p)\n", This);
1278 goto out;
1280 if((desc->dwFlags&DSBCAPS_CTRL3D) && desc->lpwfxFormat->nChannels != 1)
1282 if(This->primary->parent->is_8)
1284 /* DirectSoundBuffer8 objects aren't allowed non-mono 3D
1285 * buffers */
1286 WARN("Can't create multi-channel 3D buffers\n");
1287 goto out;
1289 ERR("Multi-channel 3D sounds are not spatialized\n");
1292 hr = DS8Data_Create(&This->buffer, desc, This->primary);
1293 if(FAILED(hr))
1294 goto out;
1295 else
1297 DS8Data *buf = This->buffer;
1299 if(buf->in_type == AL_UNSIGNED_BYTE)
1300 memset(buf->data, 0x80, buf->buf_size);
1301 else
1302 memset(buf->data, 0x00, buf->buf_size);
1304 if(This->ExtAL->BufferDataStatic)
1305 This->ExtAL->BufferDataStatic(buf->buffers[0], buf->buf_format,
1306 buf->data, buf->buf_size,
1307 buf->format.Format.nSamplesPerSec);
1308 else if(This->ExtAL->BufferSamplesSOFT)
1309 This->ExtAL->BufferSamplesSOFT(buf->buffers[0],
1310 buf->format.Format.nSamplesPerSec, buf->buf_format,
1311 buf->buf_size/buf->format.Format.nBlockAlign,
1312 buf->in_chans, buf->in_type, buf->data);
1313 else if(This->ExtAL->BufferSubData)
1314 alBufferData(buf->buffers[0], buf->buf_format,
1315 buf->data, buf->buf_size,
1316 buf->format.Format.nSamplesPerSec);
1318 getALError();
1321 hr = DSERR_GENERIC;
1322 if(This->primary->nsources)
1324 This->source = This->primary->sources[--This->primary->nsources];
1325 alSourcef(This->source, AL_GAIN, 1.0f);
1326 alSourcef(This->source, AL_PITCH, 1.0f);
1327 getALError();
1329 else
1331 alGenSources(1, &This->source);
1332 if(alGetError() != AL_NO_ERROR)
1333 goto out;
1336 ds3dbuffer = &This->ds3dbuffer;
1337 ds3dbuffer->dwSize = sizeof(*ds3dbuffer);
1338 ds3dbuffer->vPosition.x = 0.0;
1339 ds3dbuffer->vPosition.y = 0.0;
1340 ds3dbuffer->vPosition.z = 0.0;
1341 ds3dbuffer->vVelocity.x = 0.0;
1342 ds3dbuffer->vVelocity.y = 0.0;
1343 ds3dbuffer->vVelocity.z = 0.0;
1344 ds3dbuffer->dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1345 ds3dbuffer->dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1346 ds3dbuffer->vConeOrientation.x = 0.0;
1347 ds3dbuffer->vConeOrientation.y = 0.0;
1348 ds3dbuffer->vConeOrientation.z = 1.0;
1349 ds3dbuffer->lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1350 ds3dbuffer->flMinDistance = DS3D_DEFAULTMINDISTANCE;
1351 ds3dbuffer->flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1352 ds3dbuffer->dwMode = DS3DMODE_NORMAL;
1354 if((This->buffer->dsbflags&DSBCAPS_CTRL3D))
1356 if(This->primary->auxslot != 0)
1358 alSource3i(This->source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1359 getALError();
1362 hr = IDirectSound3DBuffer_SetAllParameters(&This->IDirectSound3DBuffer_iface, ds3dbuffer, DS3D_IMMEDIATE);
1363 if(FAILED(hr))
1365 ERR("SetAllParameters failed\n");
1366 goto out;
1369 else
1371 ALuint source = This->source;
1373 if(This->primary->auxslot != 0)
1375 /* Simple hack to make reverb affect non-3D sounds too */
1376 alSource3i(source, AL_AUXILIARY_SEND_FILTER, This->primary->auxslot, 0, AL_FILTER_NULL);
1377 /*alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);*/
1380 /* Non-3D sources aren't distance attenuated */
1381 This->ds3dmode = DS3DMODE_DISABLE;
1382 alSource3f(source, AL_POSITION, 0.0f, 1.0f, 0.0f);
1383 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1384 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1385 alSourcef(source, AL_CONE_OUTER_GAIN, 1.0f);
1386 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1387 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1388 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1389 alSourcei(source, AL_CONE_INNER_ANGLE, 360);
1390 alSourcei(source, AL_CONE_OUTER_ANGLE, 360);
1391 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1392 getALError();
1394 hr = S_OK;
1396 out:
1397 popALContext();
1398 LeaveCriticalSection(This->crst);
1400 return hr;
1403 static HRESULT WINAPI DS8Buffer_Lock(IDirectSoundBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
1405 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1406 HRESULT hr;
1407 DWORD remain;
1409 TRACE("(%p)->(%u, %u, %p, %p, %p, %p, 0x%x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
1411 if(!ptr1 || !len1)
1413 WARN("Invalid pointer/len %p %p\n", ptr1, len1);
1414 return DSERR_INVALIDPARAM;
1417 EnterCriticalSection(This->crst);
1418 setALContext(This->ctx);
1420 *ptr1 = NULL;
1421 *len1 = 0;
1422 if(ptr2) *ptr2 = NULL;
1423 if(len2) *len2 = 0;
1425 hr = DSERR_INVALIDPARAM;
1426 if((flags&DSBLOCK_FROMWRITECURSOR))
1427 DS8Buffer_GetCurrentPosition(iface, NULL, &ofs);
1428 else if(ofs >= This->buffer->buf_size)
1430 WARN("Invalid ofs %u\n", ofs);
1431 goto out;
1433 if((flags&DSBLOCK_ENTIREBUFFER))
1434 bytes = This->buffer->buf_size;
1435 else if(bytes > This->buffer->buf_size)
1437 WARN("Invalid size %u\n", bytes);
1438 goto out;
1441 *ptr1 = This->buffer->data + ofs;
1442 if(ofs+bytes >= This->buffer->buf_size)
1444 *len1 = This->buffer->buf_size - ofs;
1445 remain = bytes - *len1;
1447 else
1449 *len1 = bytes;
1450 remain = 0;
1453 This->buffer->locked = TRUE;
1455 if(ptr2 && len2 && remain)
1457 *ptr2 = This->buffer->data;
1458 *len2 = remain;
1460 hr = S_OK;
1462 out:
1463 popALContext();
1464 LeaveCriticalSection(This->crst);
1465 return hr;
1468 static HRESULT WINAPI DS8Buffer_Play(IDirectSoundBuffer8 *iface, DWORD res1, DWORD prio, DWORD flags)
1470 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1471 ALint type, state = AL_STOPPED;
1472 HRESULT hr;
1473 (void)res1;
1475 TRACE("%p\n", This);
1477 EnterCriticalSection(This->crst);
1478 setALContext(This->ctx);
1480 hr = DSERR_BUFFERLOST;
1481 if(This->bufferlost)
1483 WARN("Buffer %p lost\n", This);
1484 goto out;
1487 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1489 if(!(This->buffer->dsbflags&(DSBCAPS_LOCHARDWARE|DSBCAPS_LOCSOFTWARE)))
1491 if(flags & DSBPLAY_LOCSOFTWARE)
1492 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1493 else
1494 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1497 else if(prio)
1499 ERR("Invalid priority set for non-deferred buffer %p, %u!\n", This->buffer, prio);
1500 hr = DSERR_INVALIDPARAM;
1501 goto out;
1504 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1505 if(This->buffer->numsegs > 1)
1507 This->islooping = !!(flags&DSBPLAY_LOOPING);
1508 if(state != AL_PLAYING && This->isplaying)
1509 state = AL_PLAYING;
1511 else
1513 alGetSourcei(This->source, AL_SOURCE_TYPE, &type);
1514 alSourcei(This->source, AL_LOOPING, (flags&DSBPLAY_LOOPING) ? AL_TRUE : AL_FALSE);
1516 getALError();
1518 hr = S_OK;
1519 if(state == AL_PLAYING)
1520 goto out;
1522 /* alSourceQueueBuffers will implicitly set type to streaming */
1523 if(This->buffer->numsegs == 1)
1525 if(type != AL_STATIC)
1526 alSourcei(This->source, AL_BUFFER, This->buffer->buffers[0]);
1527 alSourcePlay(This->source);
1529 if(alGetError() != AL_NO_ERROR)
1531 ERR("Couldn't start source\n");
1532 This->curidx = (This->buffer->numsegs-1+This->curidx)%This->buffer->numsegs;
1533 alSourcei(This->source, AL_BUFFER, 0);
1534 getALError();
1535 hr = DSERR_GENERIC;
1536 goto out;
1538 This->isplaying = TRUE;
1540 if(This->nnotify)
1542 DS8Buffer_addnotify(This);
1543 DS8Buffer_starttimer(This->primary);
1545 else if(This->buffer->numsegs > 1)
1546 DS8Buffer_starttimer(This->primary);
1548 out:
1549 popALContext();
1550 LeaveCriticalSection(This->crst);
1551 return hr;
1554 static HRESULT WINAPI DS8Buffer_SetCurrentPosition(IDirectSoundBuffer8 *iface, DWORD pos)
1556 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1557 HRESULT hr;
1558 TRACE("%p\n", This);
1560 EnterCriticalSection(This->crst);
1561 setALContext(This->ctx);
1563 hr = DSERR_INVALIDPARAM;
1564 if(pos >= This->buffer->buf_size)
1565 goto out;
1567 if(This->buffer->numsegs > 1)
1569 DS8Data *buf = This->buffer;
1570 This->curidx = pos/buf->segsize;
1571 if(This->curidx >= buf->numsegs)
1572 This->curidx = buf->numsegs - 1;
1573 if(This->isplaying)
1575 alSourceStop(This->source);
1576 alSourcei(This->source, AL_BUFFER, 0);
1577 getALError();
1580 else
1581 alSourcei(This->source, AL_BYTE_OFFSET, pos);
1582 This->lastpos = pos;
1583 hr = S_OK;
1585 out:
1586 popALContext();
1587 LeaveCriticalSection(This->crst);
1588 return hr;
1591 static HRESULT WINAPI DS8Buffer_SetFormat(IDirectSoundBuffer8 *iface, const WAVEFORMATEX *wfx)
1593 /* This call only works on primary buffers */
1594 WARN("(%p)->(%p)\n", iface, wfx);
1595 return DSERR_INVALIDCALL;
1598 static HRESULT WINAPI DS8Buffer_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
1600 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1601 HRESULT hr = S_OK;
1603 TRACE("(%p)->(%d)\n", iface, vol);
1605 if(vol > DSBVOLUME_MAX || vol < DSBVOLUME_MIN)
1607 WARN("Invalid volume (%d)\n", vol);
1608 return DSERR_INVALIDPARAM;
1611 EnterCriticalSection(This->crst);
1612 if(!(This->buffer->dsbflags&DSBCAPS_CTRLVOLUME))
1613 hr = DSERR_CONTROLUNAVAIL;
1614 if(SUCCEEDED(hr))
1616 ALfloat fvol = mB_to_gain(vol);
1617 setALContext(This->ctx);
1618 alSourcef(This->source, AL_GAIN, fvol);
1619 popALContext();
1621 LeaveCriticalSection(This->crst);
1623 return hr;
1626 static HRESULT WINAPI DS8Buffer_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
1628 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1629 HRESULT hr = S_OK;
1631 TRACE("(%p)->(%d)\n", iface, pan);
1633 if(pan > DSBPAN_RIGHT || pan < DSBPAN_LEFT)
1635 WARN("invalid parameter: pan = %d\n", pan);
1636 return DSERR_INVALIDPARAM;
1639 EnterCriticalSection(This->crst);
1640 if(!(This->buffer->dsbflags&DSBCAPS_CTRLPAN))
1641 hr = DSERR_CONTROLUNAVAIL;
1642 else
1644 ALfloat pos[3];
1645 pos[0] = (pan-DSBPAN_LEFT) * 2.0 / (ALfloat)(DSBPAN_RIGHT-DSBPAN_LEFT) - 1.0;
1646 /* NOTE: Strict movement along the X plane can cause the sound to jump
1647 * between left and right sharply. Using a curved path helps smooth it
1648 * out */
1649 pos[1] = sqrt(1.0 - pos[0]*pos[0]);
1650 pos[2] = 0.0;
1652 setALContext(This->ctx);
1653 alSourcefv(This->source, AL_POSITION, pos);
1654 getALError();
1655 popALContext();
1657 if(pan != 0 && This->buffer->format.Format.nChannels > 1)
1658 FIXME("Panning for multi-channel buffers is not supported\n");
1660 LeaveCriticalSection(This->crst);
1662 return hr;
1665 static HRESULT WINAPI DS8Buffer_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
1667 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1668 HRESULT hr = S_OK;
1670 TRACE("(%p)->(%u)\n", iface, freq);
1672 if(freq < DSBFREQUENCY_MIN || freq > DSBFREQUENCY_MAX)
1674 WARN("invalid parameter: freq = %d\n", freq);
1675 return DSERR_INVALIDPARAM;
1678 EnterCriticalSection(This->crst);
1679 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFREQUENCY))
1680 hr = DSERR_CONTROLUNAVAIL;
1681 else
1683 ALfloat pitch = 1.0f;
1684 if(freq != DSBFREQUENCY_ORIGINAL)
1685 pitch = freq / (ALfloat)This->buffer->format.Format.nSamplesPerSec;
1687 setALContext(This->ctx);
1688 alSourcef(This->source, AL_PITCH, pitch);
1689 getALError();
1690 popALContext();
1692 LeaveCriticalSection(This->crst);
1693 return hr;
1696 static HRESULT WINAPI DS8Buffer_Stop(IDirectSoundBuffer8 *iface)
1698 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1699 ALint state;
1701 TRACE("(%p)->()\n", iface);
1703 EnterCriticalSection(This->crst);
1704 setALContext(This->ctx);
1706 alSourcePause(This->source);
1707 getALError();
1708 /* Mac OS X doesn't immediately report state change
1709 * if Play() is immediately called after Stop, this can be fatal,
1710 * the buffer would never be restarted
1712 do {
1713 state = AL_PAUSED;
1714 alGetSourcei(This->source, AL_SOURCE_STATE, &state);
1715 if(state != AL_PLAYING)
1716 break;
1717 Sleep(1);
1718 } while(1);
1720 /* Stopped, remove from notify list */
1721 if(This->nnotify)
1723 HRESULT hr;
1724 DWORD pos = This->lastpos;
1725 hr = IDirectSoundBuffer8_GetCurrentPosition(iface, &pos, NULL);
1726 if(FAILED(hr))
1727 ERR("Own getcurrentposition failed!\n");
1728 trigger_notifies(This, This->lastpos, pos, TRUE);
1729 This->lastpos = pos;
1730 DS8Buffer_removenotify(This);
1733 This->isplaying = FALSE;
1735 popALContext();
1736 LeaveCriticalSection(This->crst);
1738 return S_OK;
1741 static HRESULT WINAPI DS8Buffer_Unlock(IDirectSoundBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
1743 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1744 DS8Data *buf = This->buffer;
1745 DWORD bufsize = buf->buf_size;
1746 DWORD_PTR ofs1, ofs2;
1747 DWORD_PTR boundary = (DWORD_PTR)buf->data;
1748 HRESULT hr;
1750 TRACE("(%p)->(%p, %u, %p, %u)\n", iface, ptr1, len1, ptr2, len2);
1752 EnterCriticalSection(This->crst);
1753 setALContext(This->ctx);
1755 This->buffer->locked = 0;
1756 hr = DSERR_INVALIDPARAM;
1758 /* Make sure offset is between boundary and boundary + bufsize */
1759 ofs1 = (DWORD_PTR)ptr1;
1760 ofs2 = (DWORD_PTR)ptr2;
1761 if(ofs1 < boundary)
1762 goto out;
1763 if(ofs2 && ofs2 != boundary)
1764 goto out;
1765 ofs1 -= boundary;
1766 ofs2 = 0;
1767 if(bufsize-ofs1 < len1 || len2 > ofs1)
1768 goto out;
1769 if(!ptr2)
1770 len2 = 0;
1772 hr = S_OK;
1773 if(!len1 && !len2)
1774 goto out;
1776 if(This->ExtAL->BufferDataStatic)
1777 goto out;
1779 if(This->ExtAL->BufferSubSamplesSOFT)
1781 WAVEFORMATEX *format = &buf->format.Format;
1783 ptr1 = (BYTE*)ptr1 - (ofs1%format->nBlockAlign);
1784 ofs1 /= format->nBlockAlign;
1785 len1 /= format->nBlockAlign;
1786 if(len1 > 0)
1787 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs1, len1,
1788 buf->in_chans, buf->in_type, ptr1);
1789 ptr2 = (BYTE*)ptr2 - (ofs2%format->nBlockAlign);
1790 ofs2 /= format->nBlockAlign;
1791 len2 /= format->nBlockAlign;
1792 if(len2 > 0)
1793 This->ExtAL->BufferSubSamplesSOFT(buf->buffers[0], ofs2, len2,
1794 buf->in_chans, buf->in_type, ptr2);
1795 getALError();
1797 else if(This->ExtAL->BufferSubData)
1799 WAVEFORMATEX *format = &buf->format.Format;
1801 len1 -= len1%format->nBlockAlign;
1802 if(len1 > 0)
1803 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr1,
1804 ofs1, len1);
1805 len2 -= len2%format->nBlockAlign;
1806 if(len2 > 0)
1807 This->ExtAL->BufferSubData(buf->buffers[0], buf->buf_format, ptr2,
1808 ofs2, len2);
1809 getALError();
1811 else
1813 alBufferData(buf->buffers[0], buf->buf_format,
1814 buf->data, buf->buf_size,
1815 buf->format.Format.nSamplesPerSec);
1816 getALError();
1819 out:
1820 if(hr != S_OK)
1821 WARN("Invalid parameters (0x%lx,%u) (%p,%u,%p,%u)\n", boundary, bufsize, ptr1, len1, ptr2, len2);
1822 popALContext();
1823 LeaveCriticalSection(This->crst);
1824 return hr;
1827 static HRESULT WINAPI DS8Buffer_Restore(IDirectSoundBuffer8 *iface)
1829 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1830 HRESULT hr;
1832 TRACE("(%p)->()\n", iface);
1834 EnterCriticalSection(This->crst);
1835 if(This->primary->parent->prio_level < DSSCL_WRITEPRIMARY ||
1836 iface == This->primary->write_emu)
1838 This->bufferlost = 0;
1839 hr = S_OK;
1841 else
1842 hr = DSERR_BUFFERLOST;
1843 LeaveCriticalSection(This->crst);
1845 return hr;
1848 static HRESULT WINAPI DS8Buffer_SetFX(IDirectSoundBuffer8 *iface, DWORD fxcount, DSEFFECTDESC *desc, DWORD *rescodes)
1850 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1851 DWORD i;
1853 TRACE("(%p)->(%u, %p, %p)\n", This, fxcount, desc, rescodes);
1855 if(!(This->buffer->dsbflags&DSBCAPS_CTRLFX))
1857 WARN("FX control not set\n");
1858 return DSERR_CONTROLUNAVAIL;
1861 if(fxcount == 0)
1863 if(desc || rescodes)
1865 WARN("Non-NULL desc and/or result pointer specified with no effects.\n");
1866 return DSERR_INVALIDPARAM;
1869 /* No effects; we can handle that */
1870 return DS_OK;
1873 if(!desc || !rescodes)
1875 WARN("NULL desc and/or result pointer specified.\n");
1876 return DSERR_INVALIDPARAM;
1879 /* We don't (currently) handle DSound effects */
1880 for(i = 0;i < fxcount;++i)
1882 FIXME("Cannot handle effect: %s\n", debugstr_guid(&desc[i].guidDSFXClass));
1883 rescodes[i] = DSFXR_FAILED;
1886 return DSERR_INVALIDPARAM;
1889 static HRESULT WINAPI DS8Buffer_AcquireResources(IDirectSoundBuffer8 *iface, DWORD flags, DWORD fxcount, DWORD *rescodes)
1891 DS8Buffer *This = impl_from_IDirectSoundBuffer8(iface);
1893 TRACE("(%p)->(%u, %u, %p)\n", This, flags, fxcount, rescodes);
1895 /* effects aren't supported at the moment.. */
1896 if(fxcount != 0 || rescodes)
1898 WARN("Non-zero effect count and/or result pointer specified with no effects.\n");
1899 return DSERR_INVALIDPARAM;
1902 EnterCriticalSection(This->crst);
1903 if((This->buffer->dsbflags&DSBCAPS_LOCDEFER))
1905 This->buffer->dsbflags &= ~(DSBCAPS_LOCSOFTWARE|DSBCAPS_LOCHARDWARE);
1906 if((flags&DSBPLAY_LOCSOFTWARE))
1907 This->buffer->dsbflags |= DSBCAPS_LOCSOFTWARE;
1908 else
1909 This->buffer->dsbflags |= DSBCAPS_LOCHARDWARE;
1911 LeaveCriticalSection(This->crst);
1913 return S_OK;
1916 static HRESULT WINAPI DS8Buffer_GetObjectInPath(IDirectSoundBuffer8 *iface, REFGUID guid, DWORD idx, REFGUID rguidiface, void **ppv)
1918 FIXME("(%p)->(%s, %u, %s, %p) : stub!\n", iface, debugstr_guid(guid), idx, debugstr_guid(rguidiface), ppv);
1919 return E_NOTIMPL;
1922 static const IDirectSoundBuffer8Vtbl DS8Buffer_Vtbl =
1924 DS8Buffer_QueryInterface,
1925 DS8Buffer_AddRef,
1926 DS8Buffer_Release,
1927 DS8Buffer_GetCaps,
1928 DS8Buffer_GetCurrentPosition,
1929 DS8Buffer_GetFormat,
1930 DS8Buffer_GetVolume,
1931 DS8Buffer_GetPan,
1932 DS8Buffer_GetFrequency,
1933 DS8Buffer_GetStatus,
1934 DS8Buffer_Initialize,
1935 DS8Buffer_Lock,
1936 DS8Buffer_Play,
1937 DS8Buffer_SetCurrentPosition,
1938 DS8Buffer_SetFormat,
1939 DS8Buffer_SetVolume,
1940 DS8Buffer_SetPan,
1941 DS8Buffer_SetFrequency,
1942 DS8Buffer_Stop,
1943 DS8Buffer_Unlock,
1944 DS8Buffer_Restore,
1945 DS8Buffer_SetFX,
1946 DS8Buffer_AcquireResources,
1947 DS8Buffer_GetObjectInPath
1950 static inline DS8Buffer *impl_from_IDirectSound3DBuffer(IDirectSound3DBuffer *iface)
1952 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSound3DBuffer_iface);
1955 static HRESULT WINAPI DS8Buffer3D_QueryInterface(IDirectSound3DBuffer *iface, REFIID riid, void **ppv)
1957 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1958 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
1961 static ULONG WINAPI DS8Buffer3D_AddRef(IDirectSound3DBuffer *iface)
1963 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1964 LONG ret;
1966 InterlockedIncrement(&This->all_ref);
1967 ret = InterlockedIncrement(&This->ds3d_ref);
1968 TRACE("new refcount %d\n", ret);
1970 return ret;
1973 static ULONG WINAPI DS8Buffer3D_Release(IDirectSound3DBuffer *iface)
1975 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1976 LONG ret;
1978 ret = InterlockedDecrement(&This->ds3d_ref);
1979 TRACE("new refcount %d\n", ret);
1980 if(InterlockedDecrement(&This->all_ref) == 0)
1981 DS8Buffer_Destroy(This);
1983 return ret;
1986 static HRESULT WINAPI DS8Buffer3D_GetAllParameters(IDirectSound3DBuffer *iface, DS3DBUFFER *ds3dbuffer)
1988 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
1989 DS3DBUFFER ds3dbuf;
1990 HRESULT hr;
1992 TRACE("%p\n", This);
1994 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
1996 WARN("Invalid parameters %p %u\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
1997 return DSERR_INVALIDPARAM;
1999 ds3dbuf.dwSize = sizeof(ds3dbuf);
2001 EnterCriticalSection(This->crst);
2002 setALContext(This->ctx);
2004 hr = IDirectSound3DBuffer_GetPosition(iface, &ds3dbuf.vPosition);
2005 if(SUCCEEDED(hr))
2006 hr = IDirectSound3DBuffer_GetVelocity(iface, &ds3dbuf.vVelocity);
2007 if(SUCCEEDED(hr))
2008 hr = IDirectSound3DBuffer_GetConeAngles(iface, &ds3dbuf.dwInsideConeAngle, &ds3dbuf.dwOutsideConeAngle);
2009 if(SUCCEEDED(hr))
2010 hr = IDirectSound3DBuffer_GetConeOrientation(iface, &ds3dbuf.vConeOrientation);
2011 if(SUCCEEDED(hr))
2012 hr = IDirectSound3DBuffer_GetConeOutsideVolume(iface, &ds3dbuf.lConeOutsideVolume);
2013 if(SUCCEEDED(hr))
2014 hr = IDirectSound3DBuffer_GetMinDistance(iface, &ds3dbuf.flMinDistance);
2015 if(SUCCEEDED(hr))
2016 hr = IDirectSound3DBuffer_GetMaxDistance(iface, &ds3dbuf.flMaxDistance);
2017 if(SUCCEEDED(hr))
2018 hr = IDirectSound3DBuffer_GetMode(iface, &ds3dbuf.dwMode);
2019 if(SUCCEEDED(hr))
2020 memcpy(ds3dbuffer, &ds3dbuf, sizeof(ds3dbuf));
2022 popALContext();
2023 LeaveCriticalSection(This->crst);
2025 return hr;
2028 static HRESULT WINAPI DS8Buffer3D_GetConeAngles(IDirectSound3DBuffer *iface, DWORD *pdwInsideConeAngle, DWORD *pdwOutsideConeAngle)
2030 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2031 ALint inangle, outangle;
2033 TRACE("(%p)->(%p, %p)\n", This, pdwInsideConeAngle, pdwOutsideConeAngle);
2034 if(!pdwInsideConeAngle || !pdwOutsideConeAngle)
2036 WARN("Invalid pointers (%p, %p)\n", pdwInsideConeAngle, pdwOutsideConeAngle);
2037 return DSERR_INVALIDPARAM;
2040 EnterCriticalSection(This->crst);
2041 setALContext(This->ctx);
2043 alGetSourcei(This->source, AL_CONE_INNER_ANGLE, &inangle);
2044 alGetSourcei(This->source, AL_CONE_OUTER_ANGLE, &outangle);
2045 getALError();
2046 *pdwInsideConeAngle = inangle;
2047 *pdwOutsideConeAngle = outangle;
2049 popALContext();
2050 LeaveCriticalSection(This->crst);
2052 return S_OK;
2055 static HRESULT WINAPI DS8Buffer3D_GetConeOrientation(IDirectSound3DBuffer *iface, D3DVECTOR *orient)
2057 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2058 ALfloat dir[3];
2060 TRACE("(%p)->(%p)\n", This, orient);
2061 if(!orient)
2063 WARN("Invalid pointer\n");
2064 return DSERR_INVALIDPARAM;
2067 EnterCriticalSection(This->crst);
2068 setALContext(This->ctx);
2070 alGetSourcefv(This->source, AL_DIRECTION, dir);
2071 getALError();
2072 orient->x = dir[0];
2073 orient->y = dir[1];
2074 orient->z = -dir[2];
2076 popALContext();
2077 LeaveCriticalSection(This->crst);
2079 return S_OK;
2082 static HRESULT WINAPI DS8Buffer3D_GetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG *vol)
2084 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2085 ALfloat gain;
2087 TRACE("(%p)->(%p)\n", This, vol);
2088 if(!vol)
2090 WARN("Invalid pointer\n");
2091 return DSERR_INVALIDPARAM;
2094 EnterCriticalSection(This->crst);
2095 setALContext(This->ctx);
2097 alGetSourcef(This->source, AL_CONE_OUTER_GAIN, &gain);
2098 getALError();
2099 *vol = gain_to_mB(gain);
2100 *vol = max(*vol, DSBVOLUME_MIN);
2101 *vol = min(*vol, DSBVOLUME_MAX);
2103 popALContext();
2104 LeaveCriticalSection(This->crst);
2105 return S_OK;
2108 static HRESULT WINAPI DS8Buffer3D_GetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE *maxdist)
2110 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2111 ALfloat dist;
2113 TRACE("(%p)->(%p)\n", This, maxdist);
2114 if(!maxdist)
2116 WARN("Invalid pointer\n");
2117 return DSERR_INVALIDPARAM;
2120 EnterCriticalSection(This->crst);
2121 setALContext(This->ctx);
2123 alGetSourcef(This->source, AL_MAX_DISTANCE, &dist);
2124 getALError();
2125 *maxdist = dist;
2127 popALContext();
2128 LeaveCriticalSection(This->crst);
2130 return S_OK;
2133 static HRESULT WINAPI DS8Buffer3D_GetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE *mindist)
2135 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2136 ALfloat dist;
2138 TRACE("(%p)->(%p)\n", This, mindist);
2139 if(!mindist)
2141 WARN("Invalid pointer\n");
2142 return DSERR_INVALIDPARAM;
2145 EnterCriticalSection(This->crst);
2146 setALContext(This->ctx);
2148 alGetSourcef(This->source, AL_REFERENCE_DISTANCE, &dist);
2149 getALError();
2150 *mindist = dist;
2152 popALContext();
2153 LeaveCriticalSection(This->crst);
2155 return S_OK;
2158 static HRESULT WINAPI DS8Buffer3D_GetMode(IDirectSound3DBuffer *iface, DWORD *mode)
2160 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2162 TRACE("(%p)->(%p)\n", This, mode);
2163 if(!mode)
2165 WARN("Invalid pointer\n");
2166 return DSERR_INVALIDPARAM;
2169 EnterCriticalSection(This->crst);
2170 *mode = This->ds3dmode;
2171 LeaveCriticalSection(This->crst);
2173 return S_OK;
2176 static HRESULT WINAPI DS8Buffer3D_GetPosition(IDirectSound3DBuffer *iface, D3DVECTOR *pos)
2178 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2179 ALfloat alpos[3];
2181 TRACE("(%p)->(%p)\n", This, pos);
2182 if(!pos)
2184 WARN("Invalid pointer\n");
2185 return DSERR_INVALIDPARAM;
2188 EnterCriticalSection(This->crst);
2189 setALContext(This->ctx);
2191 alGetSourcefv(This->source, AL_POSITION, alpos);
2192 getALError();
2193 pos->x = alpos[0];
2194 pos->y = alpos[1];
2195 pos->z = -alpos[2];
2197 popALContext();
2198 LeaveCriticalSection(This->crst);
2200 return S_OK;
2203 static HRESULT WINAPI DS8Buffer3D_GetVelocity(IDirectSound3DBuffer *iface, D3DVECTOR *vel)
2205 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2206 ALfloat alvel[3];
2208 TRACE("(%p)->(%p)\n", This, vel);
2209 if(!vel)
2211 WARN("Invalid pointer\n");
2212 return DSERR_INVALIDPARAM;
2215 EnterCriticalSection(This->crst);
2216 setALContext(This->ctx);
2218 alGetSourcefv(This->source, AL_VELOCITY, alvel);
2219 getALError();
2220 vel->x = alvel[0];
2221 vel->y = alvel[1];
2222 vel->z = -alvel[2];
2224 popALContext();
2225 LeaveCriticalSection(This->crst);
2227 return S_OK;
2230 static HRESULT WINAPI DS8Buffer3D_SetAllParameters(IDirectSound3DBuffer *iface, const DS3DBUFFER *ds3dbuffer, DWORD apply)
2232 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2233 TRACE("(%p)->(%p, %u)\n", This, ds3dbuffer, apply);
2235 if(!ds3dbuffer || ds3dbuffer->dwSize < sizeof(*ds3dbuffer))
2237 WARN("Invalid DS3DBUFFER (%p, %u)\n", ds3dbuffer, ds3dbuffer ? ds3dbuffer->dwSize : 0);
2238 return DSERR_INVALIDPARAM;
2241 if(ds3dbuffer->dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2242 ds3dbuffer->dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2244 WARN("Invalid cone angles (%u, %u)\n", ds3dbuffer->dwInsideConeAngle,
2245 ds3dbuffer->dwOutsideConeAngle);
2246 return DSERR_INVALIDPARAM;
2249 if(ds3dbuffer->lConeOutsideVolume > DSBVOLUME_MAX ||
2250 ds3dbuffer->lConeOutsideVolume < DSBVOLUME_MIN)
2252 WARN("Invalid cone outside volume (%d)\n", ds3dbuffer->lConeOutsideVolume);
2253 return DSERR_INVALIDPARAM;
2256 if(ds3dbuffer->flMaxDistance < 0.0f)
2258 WARN("Invalid max distance (%f)\n", ds3dbuffer->flMaxDistance);
2259 return DSERR_INVALIDPARAM;
2262 if(ds3dbuffer->flMinDistance < 0.0f)
2264 WARN("Invalid min distance (%f)\n", ds3dbuffer->flMinDistance);
2265 return DSERR_INVALIDPARAM;
2268 if(ds3dbuffer->dwMode != DS3DMODE_NORMAL &&
2269 ds3dbuffer->dwMode != DS3DMODE_HEADRELATIVE &&
2270 ds3dbuffer->dwMode != DS3DMODE_DISABLE)
2272 WARN("Invalid mode (%u)\n", ds3dbuffer->dwMode);
2273 return DSERR_INVALIDPARAM;
2276 EnterCriticalSection(This->crst);
2277 setALContext(This->ctx);
2278 IDirectSound3DBuffer_SetPosition(iface, ds3dbuffer->vPosition.x, ds3dbuffer->vPosition.y, ds3dbuffer->vPosition.z, apply);
2279 IDirectSound3DBuffer_SetVelocity(iface, ds3dbuffer->vVelocity.x, ds3dbuffer->vVelocity.y, ds3dbuffer->vVelocity.z, apply);
2280 IDirectSound3DBuffer_SetConeAngles(iface, ds3dbuffer->dwInsideConeAngle, ds3dbuffer->dwOutsideConeAngle, apply);
2281 IDirectSound3DBuffer_SetConeOrientation(iface, ds3dbuffer->vConeOrientation.x, ds3dbuffer->vConeOrientation.y, ds3dbuffer->vConeOrientation.z, apply);
2282 IDirectSound3DBuffer_SetConeOutsideVolume(iface, ds3dbuffer->lConeOutsideVolume, apply);
2283 IDirectSound3DBuffer_SetMinDistance(iface, ds3dbuffer->flMinDistance, apply);
2284 IDirectSound3DBuffer_SetMaxDistance(iface, ds3dbuffer->flMaxDistance, apply);
2285 IDirectSound3DBuffer_SetMode(iface, ds3dbuffer->dwMode, apply);
2286 popALContext();
2287 LeaveCriticalSection(This->crst);
2289 return S_OK;
2292 static HRESULT WINAPI DS8Buffer3D_SetConeAngles(IDirectSound3DBuffer *iface, DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD apply)
2294 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2296 TRACE("(%p)->(%u, %u, %u)\n", This, dwInsideConeAngle, dwOutsideConeAngle, apply);
2297 if(dwInsideConeAngle > DS3D_MAXCONEANGLE ||
2298 dwOutsideConeAngle > DS3D_MAXCONEANGLE)
2300 WARN("Invalid cone angles (%u, %u)\n", dwInsideConeAngle, dwOutsideConeAngle);
2301 return DSERR_INVALIDPARAM;
2304 EnterCriticalSection(This->crst);
2305 if(apply == DS3D_DEFERRED)
2307 This->ds3dbuffer.dwInsideConeAngle = dwInsideConeAngle;
2308 This->ds3dbuffer.dwOutsideConeAngle = dwOutsideConeAngle;
2309 This->dirty.bit.cone_angles = 1;
2311 else
2313 setALContext(This->ctx);
2314 alSourcei(This->source, AL_CONE_INNER_ANGLE, dwInsideConeAngle);
2315 alSourcei(This->source, AL_CONE_OUTER_ANGLE, dwOutsideConeAngle);
2316 getALError();
2317 popALContext();
2319 LeaveCriticalSection(This->crst);
2321 return S_OK;
2324 static HRESULT WINAPI DS8Buffer3D_SetConeOrientation(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2326 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2328 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2330 EnterCriticalSection(This->crst);
2331 if(apply == DS3D_DEFERRED)
2333 This->ds3dbuffer.vConeOrientation.x = x;
2334 This->ds3dbuffer.vConeOrientation.y = y;
2335 This->ds3dbuffer.vConeOrientation.z = z;
2336 This->dirty.bit.cone_orient = 1;
2338 else
2340 setALContext(This->ctx);
2341 alSource3f(This->source, AL_DIRECTION, x, y, -z);
2342 getALError();
2343 popALContext();
2345 LeaveCriticalSection(This->crst);
2347 return S_OK;
2350 static HRESULT WINAPI DS8Buffer3D_SetConeOutsideVolume(IDirectSound3DBuffer *iface, LONG vol, DWORD apply)
2352 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2354 TRACE("(%p)->(%u, %u)\n", This, vol, apply);
2355 if(vol < DSBVOLUME_MIN || vol > DSBVOLUME_MAX)
2357 WARN("Invalid volume (%u)\n", vol);
2358 return DSERR_INVALIDPARAM;
2361 EnterCriticalSection(This->crst);
2362 if(apply == DS3D_DEFERRED)
2364 This->ds3dbuffer.lConeOutsideVolume = vol;
2365 This->dirty.bit.cone_outsidevolume = 1;
2367 else
2369 setALContext(This->ctx);
2370 alSourcef(This->source, AL_CONE_OUTER_GAIN, mB_to_gain(vol));
2371 getALError();
2372 popALContext();
2374 LeaveCriticalSection(This->crst);
2376 return S_OK;
2379 static HRESULT WINAPI DS8Buffer3D_SetMaxDistance(IDirectSound3DBuffer *iface, D3DVALUE maxdist, DWORD apply)
2381 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2383 TRACE("(%p)->(%f, %u)\n", This, maxdist, apply);
2384 if(maxdist < 0.0f)
2386 WARN("Invalid max distance (%f)\n", maxdist);
2387 return DSERR_INVALIDPARAM;
2390 EnterCriticalSection(This->crst);
2391 if(apply == DS3D_DEFERRED)
2393 This->ds3dbuffer.flMaxDistance = maxdist;
2394 This->dirty.bit.max_distance = 1;
2396 else
2398 setALContext(This->ctx);
2399 alSourcef(This->source, AL_MAX_DISTANCE, maxdist);
2400 getALError();
2401 popALContext();
2403 LeaveCriticalSection(This->crst);
2405 return S_OK;
2408 static HRESULT WINAPI DS8Buffer3D_SetMinDistance(IDirectSound3DBuffer *iface, D3DVALUE mindist, DWORD apply)
2410 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2412 TRACE("(%p)->(%f, %u)\n", This, mindist, apply);
2413 if(mindist < 0.0f)
2415 WARN("Invalid min distance (%f)\n", mindist);
2416 return DSERR_INVALIDPARAM;
2419 EnterCriticalSection(This->crst);
2420 if(apply == DS3D_DEFERRED)
2422 This->ds3dbuffer.flMinDistance = mindist;
2423 This->dirty.bit.min_distance = 1;
2425 else
2427 setALContext(This->ctx);
2428 alSourcef(This->source, AL_REFERENCE_DISTANCE, mindist);
2429 getALError();
2430 popALContext();
2432 LeaveCriticalSection(This->crst);
2434 return S_OK;
2437 static HRESULT WINAPI DS8Buffer3D_SetMode(IDirectSound3DBuffer *iface, DWORD mode, DWORD apply)
2439 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2441 TRACE("(%p)->(%u, %u)\n", This, mode, apply);
2442 if(mode != DS3DMODE_NORMAL && mode != DS3DMODE_HEADRELATIVE &&
2443 mode != DS3DMODE_DISABLE)
2445 WARN("Invalid mode (%u)\n", mode);
2446 return DSERR_INVALIDPARAM;
2449 EnterCriticalSection(This->crst);
2450 if(apply == DS3D_DEFERRED)
2452 This->ds3dbuffer.dwMode = mode;
2453 This->dirty.bit.mode = 1;
2455 else
2457 setALContext(This->ctx);
2458 alSourcei(This->source, AL_SOURCE_RELATIVE,
2459 (mode != DS3DMODE_NORMAL) ? AL_TRUE : AL_FALSE);
2460 alSourcef(This->source, AL_ROLLOFF_FACTOR,
2461 (mode == DS3DMODE_DISABLE) ? 0.0f : This->primary->rollofffactor);
2462 This->ds3dmode = mode;
2463 getALError();
2464 popALContext();
2466 LeaveCriticalSection(This->crst);
2468 return S_OK;
2471 static HRESULT WINAPI DS8Buffer3D_SetPosition(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2473 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2475 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2477 EnterCriticalSection(This->crst);
2478 if(apply == DS3D_DEFERRED)
2480 This->ds3dbuffer.vPosition.x = x;
2481 This->ds3dbuffer.vPosition.y = y;
2482 This->ds3dbuffer.vPosition.z = z;
2483 This->dirty.bit.pos = 1;
2485 else
2487 setALContext(This->ctx);
2488 alSource3f(This->source, AL_POSITION, x, y, -z);
2489 getALError();
2490 popALContext();
2492 LeaveCriticalSection(This->crst);
2494 return S_OK;
2497 static HRESULT WINAPI DS8Buffer3D_SetVelocity(IDirectSound3DBuffer *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply)
2499 DS8Buffer *This = impl_from_IDirectSound3DBuffer(iface);
2501 TRACE("(%p)->(%f, %f, %f, %u)\n", This, x, y, z, apply);
2503 EnterCriticalSection(This->crst);
2504 if(apply == DS3D_DEFERRED)
2506 This->ds3dbuffer.vVelocity.x = x;
2507 This->ds3dbuffer.vVelocity.y = y;
2508 This->ds3dbuffer.vVelocity.z = z;
2509 This->dirty.bit.vel = 1;
2511 else
2513 setALContext(This->ctx);
2514 alSource3f(This->source, AL_VELOCITY, x, y, -z);
2515 getALError();
2516 popALContext();
2518 LeaveCriticalSection(This->crst);
2520 return S_OK;
2523 static const IDirectSound3DBufferVtbl DS8Buffer3d_Vtbl =
2525 DS8Buffer3D_QueryInterface,
2526 DS8Buffer3D_AddRef,
2527 DS8Buffer3D_Release,
2528 DS8Buffer3D_GetAllParameters,
2529 DS8Buffer3D_GetConeAngles,
2530 DS8Buffer3D_GetConeOrientation,
2531 DS8Buffer3D_GetConeOutsideVolume,
2532 DS8Buffer3D_GetMaxDistance,
2533 DS8Buffer3D_GetMinDistance,
2534 DS8Buffer3D_GetMode,
2535 DS8Buffer3D_GetPosition,
2536 DS8Buffer3D_GetVelocity,
2537 DS8Buffer3D_SetAllParameters,
2538 DS8Buffer3D_SetConeAngles,
2539 DS8Buffer3D_SetConeOrientation,
2540 DS8Buffer3D_SetConeOutsideVolume,
2541 DS8Buffer3D_SetMaxDistance,
2542 DS8Buffer3D_SetMinDistance,
2543 DS8Buffer3D_SetMode,
2544 DS8Buffer3D_SetPosition,
2545 DS8Buffer3D_SetVelocity
2548 static inline DS8Buffer *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
2550 return CONTAINING_RECORD(iface, DS8Buffer, IDirectSoundNotify_iface);
2553 static HRESULT WINAPI DS8BufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
2555 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2556 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2559 static ULONG WINAPI DS8BufferNot_AddRef(IDirectSoundNotify *iface)
2561 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2562 LONG ret;
2564 InterlockedIncrement(&This->all_ref);
2565 ret = InterlockedIncrement(&This->not_ref);
2566 TRACE("new refcount %d\n", ret);
2568 return ret;
2571 static ULONG WINAPI DS8BufferNot_Release(IDirectSoundNotify *iface)
2573 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2574 LONG ret;
2576 ret = InterlockedDecrement(&This->not_ref);
2577 TRACE("new refcount %d\n", ret);
2578 if(InterlockedDecrement(&This->all_ref) == 0)
2579 DS8Buffer_Destroy(This);
2581 return ret;
2584 static HRESULT WINAPI DS8BufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
2586 DS8Buffer *This = impl_from_IDirectSoundNotify(iface);
2587 DSBPOSITIONNOTIFY *nots;
2588 DWORD state;
2589 HRESULT hr;
2591 EnterCriticalSection(This->crst);
2592 hr = DSERR_INVALIDPARAM;
2593 if(count && !notifications)
2594 goto out;
2596 hr = IDirectSoundBuffer8_GetStatus(&This->IDirectSoundBuffer8_iface, &state);
2597 if(FAILED(hr))
2598 goto out;
2600 hr = DSERR_INVALIDCALL;
2601 if((state&DSBSTATUS_PLAYING))
2602 goto out;
2604 if(!count)
2606 HeapFree(GetProcessHeap(), 0, This->notify);
2607 This->notify = 0;
2608 This->nnotify = 0;
2609 hr = S_OK;
2611 else
2613 DWORD i;
2615 hr = DSERR_INVALIDPARAM;
2616 for(i = 0;i < count;++i)
2618 if(notifications[i].dwOffset >= This->buffer->buf_size &&
2619 notifications[i].dwOffset != (DWORD)DSBPN_OFFSETSTOP)
2620 goto out;
2623 hr = E_OUTOFMEMORY;
2624 nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
2625 if(!nots)
2626 goto out;
2627 memcpy(nots, notifications, count*sizeof(*nots));
2629 HeapFree(GetProcessHeap(), 0, This->notify);
2630 This->notify = nots;
2631 This->nnotify = count;
2633 hr = S_OK;
2636 out:
2637 LeaveCriticalSection(This->crst);
2638 return hr;
2641 static const IDirectSoundNotifyVtbl DS8BufferNot_Vtbl =
2643 DS8BufferNot_QueryInterface,
2644 DS8BufferNot_AddRef,
2645 DS8BufferNot_Release,
2646 DS8BufferNot_SetNotificationPositions
2649 /* NOTE: Due to some apparent quirks in DSound, the listener properties are
2650 handled through secondary buffers. */
2651 static inline DS8Buffer *impl_from_IKsPropertySet(IKsPropertySet *iface)
2653 return CONTAINING_RECORD(iface, DS8Buffer, IKsPropertySet_iface);
2656 static HRESULT WINAPI DS8BufferProp_QueryInterface(IKsPropertySet *iface, REFIID riid, void **ppv)
2658 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2659 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppv);
2662 static ULONG WINAPI DS8BufferProp_AddRef(IKsPropertySet *iface)
2664 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2665 LONG ret;
2667 InterlockedIncrement(&This->all_ref);
2668 ret = InterlockedIncrement(&This->prop_ref);
2669 TRACE("new refcount %d\n", ret);
2671 return ret;
2674 static ULONG WINAPI DS8BufferProp_Release(IKsPropertySet *iface)
2676 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2677 LONG ret;
2679 ret = InterlockedDecrement(&This->prop_ref);
2680 TRACE("new refcount %d\n", ret);
2681 if(InterlockedDecrement(&This->all_ref) == 0)
2682 DS8Buffer_Destroy(This);
2684 return ret;
2687 static HRESULT WINAPI DS8BufferProp_Get(IKsPropertySet *iface,
2688 REFGUID guidPropSet, ULONG dwPropID,
2689 LPVOID pInstanceData, ULONG cbInstanceData,
2690 LPVOID pPropData, ULONG cbPropData,
2691 PULONG pcbReturned)
2693 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2694 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2696 TRACE("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", iface, debugstr_guid(guidPropSet),
2697 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
2699 if(!pcbReturned)
2700 return E_POINTER;
2701 *pcbReturned = 0;
2703 #if 0
2704 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2707 else
2708 #endif
2710 /* Not a known buffer/source property. Pass it to the listener */
2711 hr = IKsPropertySet_Get(&This->primary->IKsPropertySet_iface, guidPropSet,
2712 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData,
2713 pcbReturned);
2716 return hr;
2719 static HRESULT WINAPI DS8BufferProp_Set(IKsPropertySet *iface,
2720 REFGUID guidPropSet, ULONG dwPropID,
2721 LPVOID pInstanceData, ULONG cbInstanceData,
2722 LPVOID pPropData, ULONG cbPropData)
2724 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2725 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2727 TRACE("(%p)->(%s, %u, %p, %u, %p, %u)\n", iface, debugstr_guid(guidPropSet),
2728 dwPropID, pInstanceData, cbInstanceData, pPropData, cbPropData);
2730 #if 0
2731 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2734 else
2735 #endif
2737 /* Not a known buffer/source property. Pass it to the listener */
2738 hr = IKsPropertySet_Set(&This->primary->IKsPropertySet_iface, guidPropSet,
2739 dwPropID, pInstanceData, cbInstanceData, pPropData,
2740 cbPropData);
2743 return hr;
2746 static HRESULT WINAPI DS8BufferProp_QuerySupport(IKsPropertySet *iface,
2747 REFGUID guidPropSet, ULONG dwPropID,
2748 PULONG pTypeSupport)
2750 DS8Buffer *This = impl_from_IKsPropertySet(iface);
2751 HRESULT hr = E_PROP_ID_UNSUPPORTED;
2753 TRACE("(%p)->(%s, %u, %p)\n", iface, debugstr_guid(guidPropSet), dwPropID, pTypeSupport);
2755 if(!pTypeSupport)
2756 return E_POINTER;
2757 *pTypeSupport = 0;
2759 #if 0
2760 if(IsEqualIID(guidPropSet, &DSPROPSETID_EAX20_BufferProperties))
2763 else
2764 #endif
2766 /* Not a known buffer/source property. Pass it to the listener */
2767 hr = IKsPropertySet_QuerySupport(&This->primary->IKsPropertySet_iface,
2768 guidPropSet, dwPropID, pTypeSupport);
2771 return hr;
2774 static const IKsPropertySetVtbl DS8BufferProp_Vtbl =
2776 DS8BufferProp_QueryInterface,
2777 DS8BufferProp_AddRef,
2778 DS8BufferProp_Release,
2779 DS8BufferProp_Get,
2780 DS8BufferProp_Set,
2781 DS8BufferProp_QuerySupport