Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
a7d6ed8e
Commit
a7d6ed8e
authored
Jun 13, 2007
by
Maarten Lankhorst
Committed by
Alexandre Julliard
Jun 22, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dsound: Simplify mixing by removing remixing support, and fix its waveout breakage.
Based on a patch by Peter Dons Tychsen.
parent
95912460
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
390 additions
and
613 deletions
+390
-613
buffer.c
dlls/dsound/buffer.c
+51
-61
dsound_main.c
dlls/dsound/dsound_main.c
+1
-8
dsound_private.h
dlls/dsound/dsound_private.h
+5
-11
mixer.c
dlls/dsound/mixer.c
+281
-514
primary.c
dlls/dsound/primary.c
+50
-17
sound3d.c
dlls/dsound/sound3d.c
+2
-2
No files found.
dlls/dsound/buffer.c
View file @
a7d6ed8e
...
...
@@ -236,8 +236,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
hres
=
IDsDriverBuffer_SetVolumePan
(
This
->
hwbuf
,
&
(
This
->
volpan
));
if
(
hres
!=
DS_OK
)
WARN
(
"IDsDriverBuffer_SetVolumePan failed
\n
"
);
}
else
DSOUND_ForceRemix
(
This
);
}
}
LeaveCriticalSection
(
&
(
This
->
lock
));
...
...
@@ -297,8 +296,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
This
->
freqAdjust
=
(
freq
<<
DSOUND_FREQSHIFT
)
/
This
->
device
->
pwfx
->
nSamplesPerSec
;
This
->
nAvgBytesPerSec
=
freq
*
This
->
pwfx
->
nBlockAlign
;
DSOUND_RecalcFormat
(
This
);
if
(
!
This
->
hwbuf
)
DSOUND_ForceRemix
(
This
);
}
LeaveCriticalSection
(
&
(
This
->
lock
));
...
...
@@ -424,29 +421,51 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
/* we need to know how far away we are from there */
if
(
pmix
<
pplay
)
pmix
+=
device
->
buflen
;
/* wraparound */
pmix
-=
pplay
;
/* detect buffer underrun */
/* detect buffer underrun (sanity) */
if
(
pwrite
<
pplay
)
pwrite
+=
device
->
buflen
;
/* wraparound */
pwrite
-=
pplay
;
if
(
pmix
>
(
ds_snd_queue_max
*
device
->
fraglen
+
pwrite
+
device
->
writelead
))
{
WARN
(
"detected an underrun: primary queue was %d
\n
"
,
pmix
);
ERR
(
"detected an underrun: primary queue was %d
\n
"
,
pmix
);
pmix
=
0
;
}
TRACE
(
"primary back-samples=%d
\n
"
,
pmix
);
/* divide the offset by its sample size */
pmix
/=
device
->
pwfx
->
nBlockAlign
;
TRACE
(
"primary back-samples=%d
\n
"
,
pmix
);
/* adjust for our frequency */
pmix
=
(
pmix
*
This
->
freqAdjust
)
>>
DSOUND_FREQSHIFT
;
/* multiply by our own sample size */
pmix
*=
This
->
pwfx
->
nBlockAlign
;
TRACE
(
"this back-offset=%d
\n
"
,
pmix
);
/* sanity */
if
(
pmix
>
This
->
buflen
){
ERR
(
"Bad length in CalcPlayPosition!
\n
"
);
return
0
;
}
/* subtract from our last mixed position */
while
(
bplay
<
pmix
)
bplay
+=
This
->
buflen
;
/* wraparound */
if
(
bplay
<
pmix
)
bplay
+=
This
->
buflen
;
/* wraparound */
bplay
-=
pmix
;
/* check for lead-in */
if
(
This
->
leadin
&&
((
bplay
<
This
->
startpos
)
||
(
bplay
>
This
->
buf_mixpos
)))
{
/* seems we haven't started playing yet */
TRACE
(
"this still in lead-in phase
\n
"
);
bplay
=
This
->
startpos
;
}
/* sanity */
if
(
bplay
>
This
->
buflen
){
ERR
(
"Bad play position in CalcPlayPosition!
\n
"
);
return
0
;
}
/* return the result */
return
bplay
;
}
...
...
@@ -469,13 +488,13 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
*
playpos
=
This
->
buf_mixpos
;
}
else
if
(
playpos
)
{
DWORD
pplay
,
pwrite
;
/* let's get this exact; first, recursively call GetPosition on the primary */
/* get primary lock, before messing with primary/device data */
EnterCriticalSection
(
&
(
This
->
device
->
mixlock
));
/* let's get this exact; first, recursively call GetPosition on the primary */
if
(
DSOUND_PrimaryGetPosition
(
This
->
device
,
&
pplay
,
&
pwrite
)
!=
DS_OK
)
WARN
(
"DSOUND_PrimaryGetPosition failed
\n
"
);
/* detect HEL mode underrun */
if
(
!
(
This
->
device
->
hwbuf
||
This
->
device
->
pwqueue
))
TRACE
(
"detected an underrun
\n
"
);
if
((
This
->
dsbd
.
dwFlags
&
DSBCAPS_GETCURRENTPOSITION2
)
||
This
->
device
->
hwbuf
)
{
/* calculate play position using this */
*
playpos
=
DSOUND_CalcPlayPosition
(
This
,
pplay
,
pwrite
);
...
...
@@ -489,7 +508,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
wp
=
(
This
->
device
->
pwplay
+
ds_hel_margin
)
*
This
->
device
->
fraglen
;
wp
%=
This
->
device
->
buflen
;
*
playpos
=
DSOUND_CalcPlayPosition
(
This
,
wp
,
pwrite
);
TRACE
(
"Using non-GETCURRENTPOSITION2
\n
"
);
}
LeaveCriticalSection
(
&
(
This
->
device
->
mixlock
));
}
if
(
writepos
)
...
...
@@ -504,7 +525,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
}
if
(
playpos
)
This
->
last_playpos
=
*
playpos
;
TRACE
(
"playpos = %d, writepos = %d (%p, time=%d)
\n
"
,
playpos
?*
playpos
:
0
,
writepos
?*
writepos
:
0
,
This
,
GetTickCount
());
TRACE
(
"playpos = %d, writepos = %d, buflen=%d (%p, time=%d)
\n
"
,
playpos
?*
playpos
:
0
,
writepos
?*
writepos
:
0
,
This
->
buflen
,
This
,
GetTickCount
());
return
DS_OK
;
}
...
...
@@ -610,19 +634,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
return
DSERR_INVALIDPARAM
;
}
/* **** */
EnterCriticalSection
(
&
(
This
->
lock
));
if
((
writebytes
==
This
->
buflen
)
&&
((
This
->
state
==
STATE_STARTING
)
||
(
This
->
state
==
STATE_PLAYING
)))
/* some games, like Half-Life, try to be clever (not) and
* keep one secondary buffer, and mix sounds into it itself,
* locking the entire buffer every time... so we can just forget
* about tracking the last-written-to-position... */
This
->
probably_valid_to
=
(
DWORD
)
-
1
;
else
This
->
probably_valid_to
=
writecursor
;
if
(
!
(
This
->
device
->
drvdesc
.
dwFlags
&
DSDDESC_DONTNEEDSECONDARYLOCK
)
&&
This
->
hwbuf
)
{
hres
=
IDsDriverBuffer_Lock
(
This
->
hwbuf
,
lplpaudioptr1
,
audiobytes1
,
...
...
@@ -635,7 +649,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
return
hres
;
}
}
else
{
BOOL
remix
=
FALSE
;
if
(
writecursor
+
writebytes
<=
This
->
buflen
)
{
*
(
LPBYTE
*
)
lplpaudioptr1
=
This
->
buffer
->
memory
+
writecursor
;
*
audiobytes1
=
writebytes
;
...
...
@@ -643,6 +656,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
*
(
LPBYTE
*
)
lplpaudioptr2
=
NULL
;
if
(
audiobytes2
)
*
audiobytes2
=
0
;
TRACE
(
"Locked %p(%i bytes) and %p(%i bytes) writecursor=%d
\n
"
,
*
(
LPBYTE
*
)
lplpaudioptr1
,
*
audiobytes1
,
lplpaudioptr2
?
*
(
LPBYTE
*
)
lplpaudioptr2
:
NULL
,
audiobytes2
?
*
audiobytes2
:
0
,
writecursor
);
TRACE
(
"->%d.0
\n
"
,
writebytes
);
}
else
{
*
(
LPBYTE
*
)
lplpaudioptr1
=
This
->
buffer
->
memory
+
writecursor
;
...
...
@@ -651,30 +666,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
*
(
LPBYTE
*
)
lplpaudioptr2
=
This
->
buffer
->
memory
;
if
(
audiobytes2
)
*
audiobytes2
=
writebytes
-
(
This
->
buflen
-
writecursor
);
TRACE
(
"->%d.%d
\n
"
,
*
audiobytes1
,
audiobytes2
?*
audiobytes2
:
0
);
}
if
(
This
->
state
==
STATE_PLAYING
)
{
/* if the segment between playpos and buf_mixpos is touched,
* we need to cancel some mixing */
/* we'll assume that the app always calls GetCurrentPosition before
* locking a playing buffer, so that last_playpos is up-to-date */
if
(
This
->
buf_mixpos
>=
This
->
last_playpos
)
{
if
(
This
->
buf_mixpos
>
writecursor
&&
This
->
last_playpos
<
writecursor
+
writebytes
)
remix
=
TRUE
;
}
else
{
if
(
This
->
buf_mixpos
>
writecursor
||
This
->
last_playpos
<
writecursor
+
writebytes
)
remix
=
TRUE
;
}
if
(
remix
)
{
TRACE
(
"locking prebuffered region, ouch
\n
"
);
DSOUND_MixCancelAt
(
This
,
writecursor
);
}
TRACE
(
"Locked %p(%i bytes) and %p(%i bytes) writecursor=%d
\n
"
,
*
(
LPBYTE
*
)
lplpaudioptr1
,
*
audiobytes1
,
lplpaudioptr2
?
*
(
LPBYTE
*
)
lplpaudioptr2
:
NULL
,
audiobytes2
?
*
audiobytes2
:
0
,
writecursor
);
}
}
LeaveCriticalSection
(
&
(
This
->
lock
));
/* **** */
return
DS_OK
;
}
...
...
@@ -689,9 +686,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
/* **** */
EnterCriticalSection
(
&
(
This
->
lock
));
/* start mixing from this new location instead */
newpos
%=
This
->
buflen
;
newpos
-=
newpos
%
This
->
pwfx
->
nBlockAlign
;
This
->
buf_mixpos
=
newpos
;
/* at this point, do not attempt to reset buffers, mess with primary mix position,
or anything like that to reduce latancy. The data already prebuffered cannot be changed */
/* position HW buffer if applicable */
if
(
This
->
hwbuf
)
{
hres
=
IDsDriverBuffer_SetPosition
(
This
->
hwbuf
,
This
->
buf_mixpos
);
if
(
hres
!=
DS_OK
)
...
...
@@ -735,8 +738,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
hres
=
IDsDriverBuffer_SetVolumePan
(
This
->
hwbuf
,
&
(
This
->
volpan
));
if
(
hres
!=
DS_OK
)
WARN
(
"IDsDriverBuffer_SetVolumePan failed
\n
"
);
}
else
DSOUND_ForceRemix
(
This
);
}
}
LeaveCriticalSection
(
&
(
This
->
lock
));
...
...
@@ -770,7 +772,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
LPDIRECTSOUNDBUFFER8
iface
,
LPVOID
p1
,
DWORD
x1
,
LPVOID
p2
,
DWORD
x2
)
{
IDirectSoundBufferImpl
*
This
=
(
IDirectSoundBufferImpl
*
)
iface
;
DWORD
probably_valid_to
;
HRESULT
hres
=
DS_OK
;
TRACE
(
"(%p,%p,%d,%p,%d)
\n
"
,
This
,
p1
,
x1
,
p2
,
x2
);
...
...
@@ -784,22 +785,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
WARN
(
"IDsDriverBuffer_Unlock failed
\n
"
);
}
if
(
hres
==
DS_OK
)
{
if
(
p2
)
probably_valid_to
=
(((
LPBYTE
)
p2
)
-
This
->
buffer
->
memory
)
+
x2
;
else
probably_valid_to
=
(((
LPBYTE
)
p1
)
-
This
->
buffer
->
memory
)
+
x1
;
probably_valid_to
%=
This
->
buflen
;
if
((
probably_valid_to
==
0
)
&&
((
x1
+
x2
)
==
This
->
buflen
)
&&
((
This
->
state
==
STATE_STARTING
)
||
(
This
->
state
==
STATE_PLAYING
)))
/* see IDirectSoundBufferImpl_Lock */
probably_valid_to
=
(
DWORD
)
-
1
;
This
->
probably_valid_to
=
probably_valid_to
;
}
LeaveCriticalSection
(
&
(
This
->
lock
));
/* **** */
TRACE
(
"probably_valid_to=%d
\n
"
,
This
->
probably_valid_to
);
return
hres
;
}
...
...
@@ -1044,6 +1032,8 @@ HRESULT IDirectSoundBufferImpl_Create(
dsb
->
lpVtbl
=
&
dsbvt
;
dsb
->
iks
=
NULL
;
dsb
->
remix_pos
=
0
;
/* size depends on version */
CopyMemory
(
&
dsb
->
dsbd
,
dsbd
,
dsbd
->
dwSize
);
...
...
dlls/dsound/dsound_main.c
View file @
a7d6ed8e
...
...
@@ -66,8 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound);
#define DS_HEL_QUEUE 5
/* HEL only: number of waveOut fragments ahead to queue to driver
* (this will affect HEL sound reliability and latency) */
#define DS_SND_QUEUE_MAX 28
/* max number of fragments to prebuffer */
#define DS_SND_QUEUE_MIN 12
/* min number of fragments to prebuffer */
#define DS_SND_QUEUE_MAX 10
/* max number of fragments to prebuffer */
DirectSoundDevice
*
DSOUND_renderer
[
MAXWAVEDRIVERS
];
GUID
DSOUND_renderer_guids
[
MAXWAVEDRIVERS
];
...
...
@@ -104,7 +103,6 @@ int ds_emuldriver = DS_EMULDRIVER;
int
ds_hel_margin
=
DS_HEL_MARGIN
;
int
ds_hel_queue
=
DS_HEL_QUEUE
;
int
ds_snd_queue_max
=
DS_SND_QUEUE_MAX
;
int
ds_snd_queue_min
=
DS_SND_QUEUE_MIN
;
int
ds_hw_accel
=
DS_HW_ACCEL_FULL
;
int
ds_default_playback
=
0
;
int
ds_default_capture
=
0
;
...
...
@@ -170,9 +168,6 @@ void setup_dsound_options(void)
if
(
!
get_config_key
(
hkey
,
appkey
,
"SndQueueMax"
,
buffer
,
MAX_PATH
))
ds_snd_queue_max
=
atoi
(
buffer
);
if
(
!
get_config_key
(
hkey
,
appkey
,
"SndQueueMin"
,
buffer
,
MAX_PATH
))
ds_snd_queue_min
=
atoi
(
buffer
);
if
(
!
get_config_key
(
hkey
,
appkey
,
"HardwareAcceleration"
,
buffer
,
MAX_PATH
))
{
if
(
strcmp
(
buffer
,
"Full"
)
==
0
)
ds_hw_accel
=
DS_HW_ACCEL_FULL
;
...
...
@@ -207,8 +202,6 @@ void setup_dsound_options(void)
WARN
(
"ds_hel_queue = %d (default=%d)
\n
"
,
ds_hel_queue
,
DS_HEL_QUEUE
);
if
(
ds_snd_queue_max
!=
DS_SND_QUEUE_MAX
)
WARN
(
"ds_snd_queue_max = %d (default=%d)
\n
"
,
ds_snd_queue_max
,
DS_SND_QUEUE_MAX
);
if
(
ds_snd_queue_min
!=
DS_SND_QUEUE_MIN
)
WARN
(
"ds_snd_queue_min = %d (default=%d)
\n
"
,
ds_snd_queue_min
,
DS_SND_QUEUE_MIN
);
if
(
ds_hw_accel
!=
DS_HW_ACCEL_FULL
)
WARN
(
"ds_hw_accel = %s (default=Full)
\n
"
,
ds_hw_accel
==
DS_HW_ACCEL_FULL
?
"Full"
:
...
...
dlls/dsound/dsound_private.h
View file @
a7d6ed8e
...
...
@@ -20,10 +20,11 @@
*/
/* Linux does not support better timing than 10ms */
#define DS_TIME_RES
10
/* Resolution of multimedia timer */
#define DS_TIME_RES
2
/* Resolution of multimedia timer */
#define DS_TIME_DEL 10
/* Delay of multimedia timer callback, and duration of HEL fragment */
#define DS_HEL_FRAGS 48
/* HEL only: number of waveOut fragments in primary buffer
#define DS_HEL_BUFLEN 0x8000
/* HEL: The buffer length of the emulated buffer */
#define DS_HEL_FRAGS 0x40
/* HEL only: number of waveOut fragments in primary buffer
* (changing this won't help you) */
/* direct sound hardware acceleration levels */
...
...
@@ -36,7 +37,6 @@ extern int ds_emuldriver;
extern
int
ds_hel_margin
;
extern
int
ds_hel_queue
;
extern
int
ds_snd_queue_max
;
extern
int
ds_snd_queue_min
;
extern
int
ds_hw_accel
;
extern
int
ds_default_playback
;
extern
int
ds_default_capture
;
...
...
@@ -91,7 +91,6 @@ struct DirectSoundDevice
PIDSDRIVERBUFFER
hwbuf
;
LPBYTE
buffer
;
DWORD
writelead
,
buflen
,
state
,
playpos
,
mixpos
;
BOOL
need_remix
;
int
nrofbuffers
;
IDirectSoundBufferImpl
**
buffers
;
RTL_RWLOCK
buffer_list_lock
;
...
...
@@ -168,14 +167,12 @@ struct IDirectSoundBufferImpl
DWORD
playpos
,
startpos
,
writelead
,
buflen
;
DWORD
nAvgBytesPerSec
;
DWORD
freq
;
DSVOLUMEPAN
volpan
,
cvolpan
;
DSVOLUMEPAN
volpan
;
DSBUFFERDESC
dsbd
;
/* used for frequency conversion (PerfectPitch) */
ULONG
freqAdjust
,
freqAcc
;
/* used for intelligent (well, sort of) prebuffering */
DWORD
probably_valid_to
,
last_playpos
;
DWORD
primary_mixpos
,
buf_mixpos
;
BOOL
need_remix
;
DWORD
primary_mixpos
,
buf_mixpos
,
last_playpos
,
remix_pos
;
/* IDirectSoundNotifyImpl fields */
IDirectSoundNotifyImpl
*
notify
;
...
...
@@ -439,9 +436,6 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
/* mixer.c */
void
DSOUND_CheckEvent
(
IDirectSoundBufferImpl
*
dsb
,
int
len
);
void
DSOUND_ForceRemix
(
IDirectSoundBufferImpl
*
dsb
);
void
DSOUND_MixCancelAt
(
IDirectSoundBufferImpl
*
dsb
,
DWORD
buf_writepos
);
void
DSOUND_WaveQueue
(
DirectSoundDevice
*
device
,
DWORD
mixq
);
void
DSOUND_RecalcVolPan
(
PDSVOLUMEPAN
volpan
);
void
DSOUND_AmpFactorToVolPan
(
PDSVOLUMEPAN
volpan
);
void
DSOUND_RecalcFormat
(
IDirectSoundBufferImpl
*
dsb
);
...
...
dlls/dsound/mixer.c
View file @
a7d6ed8e
...
...
@@ -3,6 +3,7 @@
* Copyright 1998 Marcus Meissner
* Copyright 1998 Rob Riggs
* Copyright 2000-2002 TransGaming Technologies, Inc.
* Copyright 2007 Peter Dons Tychsen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
...
...
@@ -315,11 +316,11 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
INT16
*
bps
=
(
INT16
*
)
buf
;
TRACE
(
"(%p,%p,%d)
\n
"
,
dsb
,
buf
,
len
);
TRACE
(
"left = %x, right = %x
\n
"
,
dsb
->
c
volpan
.
dwTotalLeftAmpFactor
,
dsb
->
c
volpan
.
dwTotalRightAmpFactor
);
TRACE
(
"left = %x, right = %x
\n
"
,
dsb
->
volpan
.
dwTotalLeftAmpFactor
,
dsb
->
volpan
.
dwTotalRightAmpFactor
);
if
((
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLPAN
)
||
(
dsb
->
c
volpan
.
lPan
==
0
))
&&
(
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLVOLUME
)
||
(
dsb
->
c
volpan
.
lVolume
==
0
))
&&
if
((
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLPAN
)
||
(
dsb
->
volpan
.
lPan
==
0
))
&&
(
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLVOLUME
)
||
(
dsb
->
volpan
.
lVolume
==
0
))
&&
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRL3D
))
return
;
/* Nothing to do */
...
...
@@ -335,7 +336,7 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
case
1
:
for
(
i
=
0
;
i
<
len
;
i
++
)
{
INT
val
=
*
bpc
-
128
;
val
=
(
val
*
dsb
->
c
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
val
=
(
val
*
dsb
->
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
*
bpc
=
val
+
128
;
bpc
++
;
}
...
...
@@ -343,10 +344,10 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
case
2
:
for
(
i
=
0
;
i
<
len
;
i
+=
2
)
{
INT
val
=
*
bpc
-
128
;
val
=
(
val
*
dsb
->
c
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
val
=
(
val
*
dsb
->
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
*
bpc
++
=
val
+
128
;
val
=
*
bpc
-
128
;
val
=
(
val
*
dsb
->
c
volpan
.
dwTotalRightAmpFactor
)
>>
16
;
val
=
(
val
*
dsb
->
volpan
.
dwTotalRightAmpFactor
)
>>
16
;
*
bpc
=
val
+
128
;
bpc
++
;
}
...
...
@@ -361,15 +362,15 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
switch
(
dsb
->
device
->
pwfx
->
nChannels
)
{
case
1
:
for
(
i
=
0
;
i
<
len
;
i
+=
2
)
{
*
bps
=
(
*
bps
*
dsb
->
c
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
*
bps
=
(
*
bps
*
dsb
->
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
bps
++
;
}
break
;
case
2
:
for
(
i
=
0
;
i
<
len
;
i
+=
4
)
{
*
bps
=
(
*
bps
*
dsb
->
c
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
*
bps
=
(
*
bps
*
dsb
->
volpan
.
dwTotalLeftAmpFactor
)
>>
16
;
bps
++
;
*
bps
=
(
*
bps
*
dsb
->
c
volpan
.
dwTotalRightAmpFactor
)
>>
16
;
*
bps
=
(
*
bps
*
dsb
->
volpan
.
dwTotalRightAmpFactor
)
>>
16
;
bps
++
;
}
break
;
...
...
@@ -447,9 +448,10 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
if
(
len
%
dsb
->
device
->
pwfx
->
nBlockAlign
)
{
INT
nBlockAlign
=
dsb
->
device
->
pwfx
->
nBlockAlign
;
ERR
(
"length not a multiple of block size, len = %d, block size = %d
\n
"
,
len
,
nBlockAlign
);
len
=
(
len
/
nBlockAlign
)
*
nBlockAlign
;
/* data alignment */
len
-=
len
%
nBlockAlign
;
/* data alignment */
}
/* Create temp buffer to hold actual resulting data */
if
((
buf
=
ibuf
=
DSOUND_tmpbuffer
(
dsb
->
device
,
len
))
==
NULL
)
return
0
;
...
...
@@ -459,6 +461,8 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
buffer, translating frequency/bits-per-sample/number-of-channels
to match the device settings */
ilen
=
DSOUND_MixerNorm
(
dsb
,
ibuf
,
len
);
/* then apply the correct volume, if necessary */
if
((
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLPAN
)
||
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLVOLUME
)
||
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRL3D
))
...
...
@@ -555,173 +559,6 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
return
len
;
}
static
void
DSOUND_PhaseCancel
(
IDirectSoundBufferImpl
*
dsb
,
DWORD
writepos
,
DWORD
len
)
{
INT
ilen
,
field
;
UINT
i
,
todo
;
BYTE
*
buf
,
*
ibuf
;
TRACE
(
"(%p,%d,%d)
\n
"
,
dsb
,
writepos
,
len
);
if
(
len
%
dsb
->
device
->
pwfx
->
nBlockAlign
)
{
INT
nBlockAlign
=
dsb
->
device
->
pwfx
->
nBlockAlign
;
ERR
(
"length not a multiple of block size, len = %d, block size = %d
\n
"
,
len
,
nBlockAlign
);
len
=
(
len
/
nBlockAlign
)
*
nBlockAlign
;
/* data alignment */
}
if
((
buf
=
ibuf
=
DSOUND_tmpbuffer
(
dsb
->
device
,
len
))
==
NULL
)
return
;
TRACE
(
"PhaseCancel (%p) len = %d, dest = %d
\n
"
,
dsb
,
len
,
writepos
);
ilen
=
DSOUND_MixerNorm
(
dsb
,
ibuf
,
len
);
if
((
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLPAN
)
||
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLVOLUME
)
||
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRL3D
))
DSOUND_MixerVol
(
dsb
,
ibuf
,
len
);
/* subtract instead of add, to phase out premixed data */
if
(
dsb
->
device
->
pwfx
->
wBitsPerSample
==
8
)
{
BYTE
*
obuf
=
dsb
->
device
->
buffer
+
writepos
;
if
((
writepos
+
len
)
<=
dsb
->
device
->
buflen
)
todo
=
len
;
else
todo
=
dsb
->
device
->
buflen
-
writepos
;
for
(
i
=
0
;
i
<
todo
;
i
++
)
{
/* 8-bit WAV is unsigned */
field
=
(
*
obuf
-
128
);
field
-=
(
*
ibuf
++
-
128
);
if
(
field
>
127
)
field
=
127
;
else
if
(
field
<
-
128
)
field
=
-
128
;
*
obuf
++
=
field
+
128
;
}
if
(
todo
<
len
)
{
todo
=
len
-
todo
;
obuf
=
dsb
->
device
->
buffer
;
for
(
i
=
0
;
i
<
todo
;
i
++
)
{
/* 8-bit WAV is unsigned */
field
=
(
*
obuf
-
128
);
field
-=
(
*
ibuf
++
-
128
);
if
(
field
>
127
)
field
=
127
;
else
if
(
field
<
-
128
)
field
=
-
128
;
*
obuf
++
=
field
+
128
;
}
}
}
else
{
INT16
*
ibufs
,
*
obufs
;
ibufs
=
(
INT16
*
)
ibuf
;
obufs
=
(
INT16
*
)(
dsb
->
device
->
buffer
+
writepos
);
if
((
writepos
+
len
)
<=
dsb
->
device
->
buflen
)
todo
=
len
/
2
;
else
todo
=
(
dsb
->
device
->
buflen
-
writepos
)
/
2
;
for
(
i
=
0
;
i
<
todo
;
i
++
)
{
/* 16-bit WAV is signed */
field
=
*
obufs
;
field
-=
*
ibufs
++
;
if
(
field
>
32767
)
field
=
32767
;
else
if
(
field
<
-
32768
)
field
=
-
32768
;
*
obufs
++
=
field
;
}
if
(
todo
<
(
len
/
2
))
{
todo
=
(
len
/
2
)
-
todo
;
obufs
=
(
INT16
*
)
dsb
->
device
->
buffer
;
for
(
i
=
0
;
i
<
todo
;
i
++
)
{
/* 16-bit WAV is signed */
field
=
*
obufs
;
field
-=
*
ibufs
++
;
if
(
field
>
32767
)
field
=
32767
;
else
if
(
field
<
-
32768
)
field
=
-
32768
;
*
obufs
++
=
field
;
}
}
}
}
static
void
DSOUND_MixCancel
(
IDirectSoundBufferImpl
*
dsb
,
DWORD
writepos
,
BOOL
cancel
)
{
DWORD
size
,
flen
,
len
,
npos
,
nlen
;
INT
iAdvance
=
dsb
->
pwfx
->
nBlockAlign
;
INT
oAdvance
=
dsb
->
device
->
pwfx
->
nBlockAlign
;
/* determine amount of premixed data to cancel */
DWORD
primary_done
=
((
dsb
->
primary_mixpos
<
writepos
)
?
dsb
->
device
->
buflen
:
0
)
+
dsb
->
primary_mixpos
-
writepos
;
TRACE
(
"(%p, %d), buf_mixpos=%d
\n
"
,
dsb
,
writepos
,
dsb
->
buf_mixpos
);
/* backtrack the mix position */
size
=
primary_done
/
oAdvance
;
flen
=
size
*
dsb
->
freqAdjust
;
len
=
(
flen
>>
DSOUND_FREQSHIFT
)
*
iAdvance
;
flen
&=
(
1
<<
DSOUND_FREQSHIFT
)
-
1
;
while
(
dsb
->
freqAcc
<
flen
)
{
len
+=
iAdvance
;
dsb
->
freqAcc
+=
1
<<
DSOUND_FREQSHIFT
;
}
len
%=
dsb
->
buflen
;
npos
=
((
dsb
->
buf_mixpos
<
len
)
?
dsb
->
buflen
:
0
)
+
dsb
->
buf_mixpos
-
len
;
if
(
dsb
->
leadin
&&
(
dsb
->
startpos
>
npos
)
&&
(
dsb
->
startpos
<=
npos
+
len
))
{
/* stop backtracking at startpos */
npos
=
dsb
->
startpos
;
len
=
((
dsb
->
buf_mixpos
<
npos
)
?
dsb
->
buflen
:
0
)
+
dsb
->
buf_mixpos
-
npos
;
flen
=
dsb
->
freqAcc
;
nlen
=
len
/
dsb
->
pwfx
->
nBlockAlign
;
nlen
=
((
nlen
<<
DSOUND_FREQSHIFT
)
+
flen
)
/
dsb
->
freqAdjust
;
nlen
*=
dsb
->
device
->
pwfx
->
nBlockAlign
;
writepos
=
((
dsb
->
primary_mixpos
<
nlen
)
?
dsb
->
device
->
buflen
:
0
)
+
dsb
->
primary_mixpos
-
nlen
;
}
dsb
->
freqAcc
-=
flen
;
dsb
->
buf_mixpos
=
npos
;
dsb
->
primary_mixpos
=
writepos
;
TRACE
(
"new buf_mixpos=%d, primary_mixpos=%d (len=%d)
\n
"
,
dsb
->
buf_mixpos
,
dsb
->
primary_mixpos
,
len
);
if
(
cancel
)
DSOUND_PhaseCancel
(
dsb
,
writepos
,
len
);
}
void
DSOUND_MixCancelAt
(
IDirectSoundBufferImpl
*
dsb
,
DWORD
buf_writepos
)
{
#if 0
DWORD i, size, flen, len, npos, nlen;
INT iAdvance = dsb->pwfx->nBlockAlign;
INT oAdvance = dsb->device->pwfx->nBlockAlign;
/* determine amount of premixed data to cancel */
DWORD buf_done =
((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
dsb->buf_mixpos - buf_writepos;
#endif
WARN
(
"(%p, %d), buf_mixpos=%d
\n
"
,
dsb
,
buf_writepos
,
dsb
->
buf_mixpos
);
/* since this is not implemented yet, just cancel *ALL* prebuffering for now
* (which is faster anyway when there's only a single secondary buffer) */
dsb
->
device
->
need_remix
=
TRUE
;
}
void
DSOUND_ForceRemix
(
IDirectSoundBufferImpl
*
dsb
)
{
TRACE
(
"(%p)
\n
"
,
dsb
);
EnterCriticalSection
(
&
dsb
->
lock
);
if
(
dsb
->
state
==
STATE_PLAYING
)
dsb
->
device
->
need_remix
=
TRUE
;
LeaveCriticalSection
(
&
dsb
->
lock
);
}
/**
* Calculate the distance between two buffer offsets, taking wraparound
* into account.
...
...
@@ -751,149 +588,70 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD wri
{
/* The buffer's primary_mixpos may be before or after the the device
* buffer's mixpos, but both must be ahead of writepos. */
DWORD
len
,
slen
;
/* determine this buffer's write position */
DWORD
buf_writepos
=
DSOUND_CalcPlayPosition
(
dsb
,
writepos
,
writepos
);
/* determine how much already-mixed data exists */
DWORD
buf_done
=
DSOUND_BufPtrDiff
(
dsb
->
buflen
,
dsb
->
buf_mixpos
,
buf_writepos
);
DWORD
primary_done
=
DSOUND_BufPtrDiff
(
dsb
->
device
->
buflen
,
dsb
->
primary_mixpos
,
writepos
);
DWORD
adv_done
=
DSOUND_BufPtrDiff
(
dsb
->
device
->
buflen
,
dsb
->
device
->
mixpos
,
writepos
);
DWORD
played
=
DSOUND_BufPtrDiff
(
dsb
->
buflen
,
buf_writepos
,
dsb
->
playpos
);
DWORD
buf_left
=
dsb
->
buflen
-
buf_writepos
;
int
still_behind
;
DWORD
primary_done
;
TRACE
(
"(%p,%d,%d,%d)
\n
"
,
dsb
,
playpos
,
writepos
,
mixlen
);
TRACE
(
"buf_writepos=%d, primary_writepos=%d
\n
"
,
buf_writepos
,
writepos
);
TRACE
(
"buf_done=%d, primary_done=%d
\n
"
,
buf_done
,
primary_done
);
TRACE
(
"buf_mixpos=%d, primary_mixpos=%d, mixlen=%d
\n
"
,
dsb
->
buf_mixpos
,
dsb
->
primary_mixpos
,
mixlen
);
TRACE
(
"looping=%d, startpos=%d, leadin=%d
\n
"
,
dsb
->
playflags
,
dsb
->
startpos
,
dsb
->
leadin
);
TRACE
(
"writepos=%d, buf_mixpos=%d, primary_mixpos=%d, mixlen=%d
\n
"
,
writepos
,
dsb
->
buf_mixpos
,
dsb
->
primary_mixpos
,
mixlen
);
TRACE
(
"looping=%d, startpos=%d, leadin=%d, buflen=%d
\n
"
,
dsb
->
playflags
,
dsb
->
startpos
,
dsb
->
leadin
,
dsb
->
buflen
);
/* check for notification positions */
if
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_CTRLPOSITIONNOTIFY
&&
dsb
->
state
!=
STATE_STARTING
)
{
DSOUND_CheckEvent
(
dsb
,
played
);
DSOUND_CheckEvent
(
dsb
,
mixlen
);
}
/* save write position for non-GETCURRENTPOSITION2... */
dsb
->
playpos
=
buf_
writepos
;
dsb
->
playpos
=
writepos
;
/* check whether CalcPlayPosition detected a mixing underrun */
if
((
buf_done
==
0
)
&&
(
dsb
->
primary_mixpos
!=
writepos
))
{
/* it did, but did we have more to play? */
if
((
dsb
->
playflags
&
DSBPLAY_LOOPING
)
||
(
dsb
->
buf_mixpos
<
dsb
->
buflen
))
{
/* yes, have to recover */
ERR
(
"underrun on sound buffer %p
\n
"
,
dsb
);
TRACE
(
"recovering from underrun: primary_mixpos=%d
\n
"
,
writepos
);
}
dsb
->
primary_mixpos
=
writepos
;
primary_done
=
0
;
}
/* determine how far ahead we should mix */
if
(((
dsb
->
playflags
&
DSBPLAY_LOOPING
)
||
(
dsb
->
leadin
&&
(
dsb
->
probably_valid_to
!=
0
)))
&&
!
(
dsb
->
dsbd
.
dwFlags
&
DSBCAPS_STATIC
))
{
/* if this is a streaming buffer, it typically means that
* we should defer mixing past probably_valid_to as long
* as we can, to avoid unnecessary remixing */
/* the heavy-looking calculations shouldn't be that bad,
* as any game isn't likely to be have more than 1 or 2
* streaming buffers in use at any time anyway... */
DWORD
probably_valid_left
=
(
dsb
->
probably_valid_to
==
(
DWORD
)
-
1
)
?
dsb
->
buflen
:
((
dsb
->
probably_valid_to
<
buf_writepos
)
?
dsb
->
buflen
:
0
)
+
dsb
->
probably_valid_to
-
buf_writepos
;
/* check for leadin condition */
if
((
probably_valid_left
==
0
)
&&
(
dsb
->
probably_valid_to
==
dsb
->
startpos
)
&&
dsb
->
leadin
)
probably_valid_left
=
dsb
->
buflen
;
TRACE
(
"streaming buffer probably_valid_to=%d, probably_valid_left=%d
\n
"
,
dsb
->
probably_valid_to
,
probably_valid_left
);
/* check whether the app's time is already up */
if
(
probably_valid_left
<
dsb
->
writelead
)
{
WARN
(
"probably_valid_to now within writelead, possible streaming underrun
\n
"
);
/* once we pass the point of no return,
* no reason to hold back anymore */
dsb
->
probably_valid_to
=
(
DWORD
)
-
1
;
/* we just have to go ahead and mix what we have,
* there's no telling what the app is thinking anyway */
}
else
{
/* adjust for our frequency and our sample size */
probably_valid_left
=
MulDiv
(
probably_valid_left
,
1
<<
DSOUND_FREQSHIFT
,
dsb
->
pwfx
->
nBlockAlign
*
dsb
->
freqAdjust
)
*
dsb
->
device
->
pwfx
->
nBlockAlign
;
/* check whether to clip mix_len */
if
(
probably_valid_left
<
mixlen
)
{
TRACE
(
"clipping to probably_valid_left=%d
\n
"
,
probably_valid_left
);
mixlen
=
probably_valid_left
;
}
}
}
/* cut mixlen with what's already been mixed */
if
(
mixlen
<
primary_done
)
{
/* huh? and still CalcPlayPosition didn't
* detect an underrun? */
FIXME
(
"problem with underrun detection (mixlen=%d < primary_done=%d)
\n
"
,
mixlen
,
primary_done
);
/* calculate how much pre-buffering has already been done for this buffer */
primary_done
=
DSOUND_BufPtrDiff
(
dsb
->
device
->
buflen
,
dsb
->
primary_mixpos
,
writepos
);
/* sanity */
if
(
mixlen
<
primary_done
)
{
/* Should *NEVER* happen */
ERR
(
"Fatal error. Under/Overflow? primary_done=%d, mixpos=%d, primary_mixpos=%d, writepos=%d, playpos=%d
\n
"
,
primary_done
,
dsb
->
buf_mixpos
,
dsb
->
primary_mixpos
,
writepos
,
playpos
);
return
0
;
}
len
=
mixlen
-
primary_done
;
TRACE
(
"remaining mixlen=%d
\n
"
,
len
);
if
(
len
<
dsb
->
device
->
fraglen
)
{
/* smaller than a fragment, wait until it gets larger
* before we take the mixing overhead */
TRACE
(
"mixlen not worth it, deferring mixing
\n
"
);
still_behind
=
1
;
goto
post_mix
;
}
/* take into acount already mixed data */
mixlen
=
mixlen
-
primary_done
;
TRACE
(
"mixlen (primary) = %i
\n
"
,
mixlen
);
/* ok, we know how much to mix, let's go */
still_behind
=
(
adv_done
>
primary_done
);
while
(
len
)
{
slen
=
dsb
->
device
->
buflen
-
dsb
->
primary_mixpos
;
if
(
slen
>
len
)
slen
=
len
;
slen
=
DSOUND_MixInBuffer
(
dsb
,
dsb
->
primary_mixpos
,
slen
);
/* clip to valid length */
mixlen
=
(
dsb
->
buflen
<
mixlen
)
?
dsb
->
buflen
:
mixlen
;
if
((
dsb
->
primary_mixpos
<
dsb
->
device
->
mixpos
)
&&
(
dsb
->
primary_mixpos
+
slen
>=
dsb
->
device
->
mixpos
))
still_behind
=
FALSE
;
TRACE
(
"primary_done=%d, mixlen (buffer)=%d
\n
"
,
primary_done
,
mixlen
);
dsb
->
primary_mixpos
+=
slen
;
len
-=
slen
;
/* mix more data */
mixlen
=
DSOUND_MixInBuffer
(
dsb
,
dsb
->
primary_mixpos
,
mixlen
);
/* increase mix position */
dsb
->
primary_mixpos
+=
mixlen
;
dsb
->
primary_mixpos
%=
dsb
->
device
->
buflen
;
if
((
dsb
->
state
==
STATE_STOPPED
)
||
!
slen
)
break
;
}
TRACE
(
"new primary_mixpos=%d, primary_advbase=%d
\n
"
,
dsb
->
primary_mixpos
,
dsb
->
device
->
mixpos
);
TRACE
(
"mixed data len=%d, still_behind=%d
\n
"
,
mixlen
-
len
,
still_behind
);
TRACE
(
"new primary_mixpos=%d, mixed data len=%d, buffer left = %d
\n
"
,
dsb
->
primary_mixpos
,
mixlen
,
(
dsb
->
buflen
-
dsb
->
buf_mixpos
));
/* re-calculate the primary done */
primary_done
=
DSOUND_BufPtrDiff
(
dsb
->
device
->
buflen
,
dsb
->
primary_mixpos
,
writepos
);
post_mix:
/* check if buffer should be considered complete */
if
(
buf_left
<
dsb
->
writelead
&&
if
(
((
dsb
->
buflen
-
dsb
->
buf_mixpos
)
<
dsb
->
writelead
)
&&
!
(
dsb
->
playflags
&
DSBPLAY_LOOPING
))
{
TRACE
(
"Buffer reached end. Stopped
\n
"
);
dsb
->
state
=
STATE_STOPPED
;
dsb
->
playpos
=
0
;
dsb
->
last_playpos
=
0
;
dsb
->
buf_mixpos
=
0
;
dsb
->
leadin
=
FALSE
;
dsb
->
need_remix
=
FALSE
;
DSOUND_CheckEvent
(
dsb
,
buf_left
);
DSOUND_CheckEvent
(
dsb
,
mixlen
);
}
/* return how far we think the primary buffer can
* advance its underrun detector...*/
if
(
still_behind
)
return
0
;
if
((
mixlen
-
len
)
<
primary_done
)
return
0
;
slen
=
DSOUND_BufPtrDiff
(
dsb
->
device
->
buflen
,
dsb
->
primary_mixpos
,
dsb
->
device
->
mixpos
);
if
(
slen
>
mixlen
)
{
/* the primary_done and still_behind checks above should have worked */
FIXME
(
"problem with advancement calculation (advlen=%d > mixlen=%d)
\n
"
,
slen
,
mixlen
);
slen
=
0
;
}
return
slen
;
/* Report back the total prebuffered amount for this buffer */
return
primary_done
;
}
/**
...
...
@@ -906,127 +664,130 @@ post_mix:
* (beyond the current writepos)
* recover = true if the sound device may have been reset and the write
* position in the device buffer changed
* all_stopped = reports back if all buffers have stopped
*
* Returns: the length beyond the writepos that was mixed to.
*/
static
DWORD
DSOUND_MixToPrimary
(
const
DirectSoundDevice
*
device
,
DWORD
playpos
,
DWORD
writepos
,
DWORD
mixlen
,
BOOL
recover
)
DWORD
mixlen
,
BOOL
recover
,
BOOL
*
all_stopped
)
{
INT
i
,
len
,
maxlen
=
0
;
INT
i
,
len
;
DWORD
minlen
=
0
;
IDirectSoundBufferImpl
*
dsb
;
/* unless we find a running buffer, all have stopped */
*
all_stopped
=
TRUE
;
TRACE
(
"(%d,%d,%d,%d)
\n
"
,
playpos
,
writepos
,
mixlen
,
recover
);
for
(
i
=
0
;
i
<
device
->
nrofbuffers
;
i
++
)
{
dsb
=
device
->
buffers
[
i
];
TRACE
(
"MixToPrimary for %p, state=%d
\n
"
,
dsb
,
dsb
->
state
);
if
(
dsb
->
buflen
&&
dsb
->
state
&&
!
dsb
->
hwbuf
)
{
TRACE
(
"Checking %p, mixlen=%d
\n
"
,
dsb
,
mixlen
);
EnterCriticalSection
(
&
(
dsb
->
lock
));
/* if buffer is stopping it is stopped now */
if
(
dsb
->
state
==
STATE_STOPPING
)
{
DSOUND_MixCancel
(
dsb
,
writepos
,
TRUE
);
dsb
->
state
=
STATE_STOPPED
;
DSOUND_CheckEvent
(
dsb
,
0
);
}
else
{
/* if recovering, reset the mix position */
if
((
dsb
->
state
==
STATE_STARTING
)
||
recover
)
{
dsb
->
primary_mixpos
=
writepos
;
dsb
->
cvolpan
=
dsb
->
volpan
;
dsb
->
need_remix
=
FALSE
;
}
else
if
(
dsb
->
need_remix
)
{
DSOUND_MixCancel
(
dsb
,
writepos
,
TRUE
);
dsb
->
cvolpan
=
dsb
->
volpan
;
dsb
->
need_remix
=
FALSE
;
}
/* mix next buffer into the main buffer */
len
=
DSOUND_MixOne
(
dsb
,
playpos
,
writepos
,
mixlen
);
/* if the buffer was starting, it must be playing now */
if
(
dsb
->
state
==
STATE_STARTING
)
dsb
->
state
=
STATE_PLAYING
;
maxlen
=
(
len
>
maxlen
)
?
len
:
maxlen
;
/* check if min-len should be initialized */
if
(
minlen
==
0
)
minlen
=
len
;
/* record the minimum length mixed from all buffers */
/* we only want to return the length which *all* buffers have mixed */
if
(
len
!=
0
)
minlen
=
(
len
<
minlen
)
?
len
:
minlen
;
}
if
(
dsb
->
state
!=
STATE_STOPPED
){
*
all_stopped
=
FALSE
;
}
LeaveCriticalSection
(
&
(
dsb
->
lock
));
}
}
return
maxlen
;
TRACE
(
"Mixed at least %d from all buffers
\n
"
,
minlen
);
return
minlen
;
}
static
void
DSOUND_MixReset
(
DirectSoundDevice
*
device
,
DWORD
writepos
)
/**
* Add buffers to the emulated wave device system.
*
* device = The current dsound playback device
* force = If TRUE, the function will buffer up as many frags as possible,
* even though and will ignore the actual state of the primary buffer.
*
* Returns: None
*/
static
void
DSOUND_WaveQueue
(
DirectSoundDevice
*
device
,
BOOL
force
)
{
INT
i
;
IDirectSoundBufferImpl
*
dsb
;
int
nfiller
;
DWORD
prebuf_frags
,
wave_writepos
,
wave_fragpos
,
i
;
TRACE
(
"(%p)
\n
"
,
device
);
TRACE
(
"(%p,%d)
\n
"
,
device
,
writepos
);
/* calculate the current wave frag position */
wave_fragpos
=
(
device
->
pwplay
+
device
->
pwqueue
)
%
DS_HEL_FRAGS
;
/*
the sound of silence
*/
nfiller
=
device
->
pwfx
->
wBitsPerSample
==
8
?
128
:
0
;
/*
calculte the current wave write position
*/
wave_writepos
=
wave_fragpos
*
device
->
fraglen
;
/* reset all buffer mix positions */
for
(
i
=
0
;
i
<
device
->
nrofbuffers
;
i
++
)
{
dsb
=
device
->
buffers
[
i
];
TRACE
(
"wave_fragpos = %i, wave_writepos = %i, pwqueue = %i, ds_hel_queue= %i
\n
"
,
wave_fragpos
,
wave_writepos
,
device
->
pwqueue
,
ds_hel_queue
);
if
(
dsb
->
buflen
&&
dsb
->
state
&&
!
dsb
->
hwbuf
)
{
TRACE
(
"Resetting %p
\n
"
,
dsb
);
EnterCriticalSection
(
&
(
dsb
->
lock
));
if
(
dsb
->
state
==
STATE_STOPPING
)
{
dsb
->
state
=
STATE_STOPPED
;
}
else
if
(
dsb
->
state
==
STATE_STARTING
)
{
/* nothing */
}
else
{
DSOUND_MixCancel
(
dsb
,
writepos
,
FALSE
);
dsb
->
cvolpan
=
dsb
->
volpan
;
dsb
->
need_remix
=
FALSE
;
}
LeaveCriticalSection
(
&
(
dsb
->
lock
));
if
(
force
==
FALSE
){
/* check remaining prebuffered frags */
prebuf_frags
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
device
->
mixpos
,
wave_writepos
);
prebuf_frags
=
prebuf_frags
/
device
->
fraglen
;
}
else
{
/* buffer the maximum amount of frags */
prebuf_frags
=
device
->
prebuf
;
}
/* wipe out premixed data */
if
(
device
->
mixpos
<
writepos
)
{
FillMemory
(
device
->
buffer
+
writepos
,
device
->
buflen
-
writepos
,
nfiller
);
FillMemory
(
device
->
buffer
,
device
->
mixpos
,
nfiller
);
}
else
{
FillMemory
(
device
->
buffer
+
writepos
,
device
->
mixpos
-
writepos
,
nfiller
);
}
/* limit to the queue we have left */
if
((
prebuf_frags
+
device
->
pwqueue
)
>
device
->
prebuf
)
prebuf_frags
=
device
->
prebuf
-
device
->
pwqueue
;
/* reset primary mix position */
device
->
mixpos
=
writepos
;
}
TRACE
(
"prebuf_frags = %i
\n
"
,
prebuf_frags
);
static
void
DSOUND_CheckReset
(
DirectSoundDevice
*
device
,
DWORD
writepos
)
{
TRACE
(
"(%p,%d)
\n
"
,
device
,
writepos
);
if
(
device
->
need_remix
)
{
DSOUND_MixReset
(
device
,
writepos
);
device
->
need_remix
=
FALSE
;
/* maximize Half-Life performance */
device
->
prebuf
=
ds_snd_queue_min
;
device
->
precount
=
0
;
}
else
{
device
->
precount
++
;
if
(
device
->
precount
>=
4
)
{
if
(
device
->
prebuf
<
ds_snd_queue_max
)
device
->
prebuf
++
;
device
->
precount
=
0
;
}
}
TRACE
(
"premix adjust: %d
\n
"
,
device
->
prebuf
);
}
/* adjust queue */
device
->
pwqueue
+=
prebuf_frags
;
void
DSOUND_WaveQueue
(
DirectSoundDevice
*
device
,
DWORD
mixq
)
{
TRACE
(
"(%p,%d)
\n
"
,
device
,
mixq
);
if
(
mixq
+
device
->
pwqueue
>
ds_hel_queue
)
mixq
=
ds_hel_queue
-
device
->
pwqueue
;
TRACE
(
"queueing %d buffers, starting at %d
\n
"
,
mixq
,
device
->
pwwrite
);
for
(;
mixq
;
mixq
--
)
{
waveOutWrite
(
device
->
hwo
,
device
->
pwave
[
device
->
pwwrite
],
sizeof
(
WAVEHDR
)
);
device
->
pwwrite
++
;
if
(
device
->
pwwrite
>=
DS_HEL_FRAGS
)
device
->
pwwrite
=
0
;
device
->
pwqueue
++
;
/* get out of CS when calling the wave system */
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
/* queue up the new buffers */
for
(
i
=
0
;
i
<
prebuf_frags
;
i
++
)
{
TRACE
(
"queueing wave buffer %i
\n
"
,
wave_fragpos
);
waveOutWrite
(
device
->
hwo
,
device
->
pwave
[
wave_fragpos
],
sizeof
(
WAVEHDR
))
;
wave_fragpos
++
;
wave_fragpos
%=
DS_HEL_FRAGS
;
}
}
/* #define SYNC_CALLBACK */
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
TRACE
(
"queue now = %i
\n
"
,
device
->
pwqueue
);
}
/**
* Perform mixing for a Direct Sound device. That is, go through all the
...
...
@@ -1035,151 +796,164 @@ void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq)
*/
static
void
DSOUND_PerformMix
(
DirectSoundDevice
*
device
)
{
int
nfiller
;
BOOL
forced
;
HRESULT
hres
;
TRACE
(
"(%p)
\n
"
,
device
);
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
if
(
device
->
priolevel
!=
DSSCL_WRITEPRIMARY
)
{
BOOL
recover
=
FALSE
,
all_stopped
=
FALSE
;
DWORD
playpos
,
writepos
,
writelead
,
maxq
,
frag
,
prebuff_max
,
prebuff_left
,
size1
,
size2
;
LPVOID
buf1
,
buf2
;
BOOL
lock
=
(
device
->
hwbuf
&&
!
(
device
->
drvdesc
.
dwFlags
&
DSDDESC_DONTNEEDPRIMARYLOCK
));
int
nfiller
;
/* the sound of silence */
nfiller
=
device
->
pwfx
->
wBitsPerSample
==
8
?
128
:
0
;
/* whether the primary is forced to play even without secondary buffers */
forced
=
((
device
->
state
==
STATE_PLAYING
)
||
(
device
->
state
==
STATE_STARTING
));
if
(
device
->
priolevel
!=
DSSCL_WRITEPRIMARY
)
{
BOOL
paused
=
((
device
->
state
==
STATE_STOPPED
)
||
(
device
->
state
==
STATE_STARTING
));
/* FIXME: document variables */
DWORD
playpos
,
writepos
,
inq
,
maxq
,
frag
;
if
(
device
->
hwbuf
)
{
hres
=
IDsDriverBuffer_GetPosition
(
device
->
hwbuf
,
&
playpos
,
&
writepos
);
if
(
hres
)
{
WARN
(
"IDsDriverBuffer_GetPosition failed
\n
"
);
/* get the position in the primary buffer */
if
(
DSOUND_PrimaryGetPosition
(
device
,
&
playpos
,
&
writepos
)
!=
0
){
LeaveCriticalSection
(
&
(
device
->
mixlock
));
return
;
}
/* Well, we *could* do Just-In-Time mixing using the writepos,
* but that's a little bit ambitious and unnecessary... */
/* rather add our safety margin to the writepos, if we're playing */
if
(
!
paused
)
{
writepos
+=
device
->
writelead
;
writepos
%=
device
->
buflen
;
}
else
writepos
=
playpos
;
}
else
{
playpos
=
device
->
pwplay
*
device
->
fraglen
;
writepos
=
playpos
;
if
(
!
paused
)
{
writepos
+=
ds_hel_margin
*
device
->
fraglen
;
writepos
%=
device
->
buflen
;
}
}
TRACE
(
"primary playpos=%d, writepos=%d, clrpos=%d, mixpos=%d, buflen=%d
\n
"
,
playpos
,
writepos
,
device
->
playpos
,
device
->
mixpos
,
device
->
buflen
);
assert
(
device
->
playpos
<
device
->
buflen
);
/* wipe out just-played sound data */
if
(
playpos
<
device
->
playpos
)
{
FillMemory
(
device
->
buffer
+
device
->
playpos
,
device
->
buflen
-
device
->
playpos
,
nfiller
);
FillMemory
(
device
->
buffer
,
playpos
,
nfiller
);
buf1
=
device
->
buffer
+
device
->
playpos
;
buf2
=
device
->
buffer
;
size1
=
device
->
buflen
-
device
->
playpos
;
size2
=
playpos
;
if
(
lock
)
IDsDriverBuffer_Lock
(
device
->
hwbuf
,
&
buf1
,
&
size1
,
&
buf2
,
&
size2
,
device
->
playpos
,
size1
+
size2
,
0
);
FillMemory
(
buf1
,
size1
,
nfiller
);
if
(
playpos
&&
(
!
buf2
||
!
size2
))
FIXME
(
"%d: (%d, %d)=>(%d, %d) There should be an additional buffer here!!
\n
"
,
__LINE__
,
device
->
playpos
,
device
->
mixpos
,
playpos
,
writepos
);
FillMemory
(
buf2
,
size2
,
nfiller
);
if
(
lock
)
IDsDriverBuffer_Unlock
(
device
->
hwbuf
,
buf1
,
size1
,
buf2
,
size2
);
}
else
{
FillMemory
(
device
->
buffer
+
device
->
playpos
,
playpos
-
device
->
playpos
,
nfiller
);
buf1
=
device
->
buffer
+
device
->
playpos
;
buf2
=
NULL
;
size1
=
playpos
-
device
->
playpos
;
size2
=
0
;
if
(
lock
)
IDsDriverBuffer_Lock
(
device
->
hwbuf
,
&
buf1
,
&
size1
,
&
buf2
,
&
size2
,
device
->
playpos
,
size1
+
size2
,
0
);
FillMemory
(
buf1
,
size1
,
nfiller
);
if
(
buf2
&&
size2
)
{
FIXME
(
"%d: There should be no additional buffer here!!
\n
"
,
__LINE__
);
FillMemory
(
buf2
,
size2
,
nfiller
);
}
if
(
lock
)
IDsDriverBuffer_Unlock
(
device
->
hwbuf
,
buf1
,
size1
,
buf2
,
size2
);
}
device
->
playpos
=
playpos
;
EnterCriticalSection
(
&
(
device
->
mixlock
));
/* calc maximum prebuff */
prebuff_max
=
(
device
->
prebuf
*
device
->
fraglen
);
/* reset mixing if necessary */
DSOUND_CheckReset
(
device
,
writepos
);
/* check how much prebuffering is left */
inq
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
device
->
mixpos
,
writepos
);
/* find the maximum we can prebuffer */
if
(
!
paused
)
maxq
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
playpos
,
writepos
);
/* If we get the whole buffer, difference is 0, so we need to set whole buffer then */
if
(
paused
||
!
maxq
)
maxq
=
device
->
buflen
;
/* clip maxq to device->prebuf */
frag
=
device
->
prebuf
*
device
->
fraglen
;
if
(
maxq
>
frag
)
maxq
=
frag
;
/* check for consistency */
if
(
inq
>
maxq
)
{
/* the playback position must have passed our last
* mixed position, i.e. it's an underrun, or we have
* nothing more to play */
TRACE
(
"reached end of mixed data (inq=%d, maxq=%d)
\n
"
,
inq
,
maxq
);
inq
=
0
;
/* stop the playback now, to allow buffers to refill */
if
(
device
->
state
==
STATE_PLAYING
)
{
device
->
state
=
STATE_STARTING
;
}
else
if
(
device
->
state
==
STATE_STOPPING
)
{
device
->
state
=
STATE_STOPPED
;
}
else
{
/* how can we have an underrun if we aren't playing? */
WARN
(
"unexpected primary state (%d)
\n
"
,
device
->
state
);
}
#ifdef SYNC_CALLBACK
/* DSOUND_callback may need this lock */
LeaveCriticalSection
(
&
(
device
->
mixlock
));
#endif
if
(
DSOUND_PrimaryStop
(
device
)
!=
DS_OK
)
WARN
(
"DSOUND_PrimaryStop failed
\n
"
);
#ifdef SYNC_CALLBACK
EnterCriticalSection
(
&
(
device
->
mixlock
));
#endif
if
(
device
->
hwbuf
)
{
/* the Stop is supposed to reset play position to beginning of buffer */
/* unfortunately, OSS is not able to do so, so get current pointer */
hres
=
IDsDriverBuffer_GetPosition
(
device
->
hwbuf
,
&
playpos
,
NULL
);
if
(
hres
)
{
LeaveCriticalSection
(
&
(
device
->
mixlock
));
WARN
(
"IDsDriverBuffer_GetPosition failed
\n
"
);
return
;
}
}
else
{
playpos
=
device
->
pwplay
*
device
->
fraglen
;
}
writepos
=
playpos
;
device
->
playpos
=
playpos
;
/* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
prebuff_left
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
device
->
mixpos
,
playpos
);
writelead
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
writepos
,
playpos
);
/* find the maximum we can prebuffer from current write position */
maxq
=
prebuff_max
-
prebuff_left
;
maxq
=
(
writelead
<
prebuff_max
)
?
(
prebuff_max
-
writelead
)
:
0
;
TRACE
(
"prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d
\n
"
,
prebuff_left
,
device
->
prebuf
,
device
->
fraglen
,
prebuff_max
,
writelead
);
/* check for underrun. underrun occurs when the write position passes the mix position */
if
((
prebuff_left
>
prebuff_max
)
||
(
device
->
state
==
STATE_STOPPED
)
||
(
device
->
state
==
STATE_STARTING
)){
TRACE
(
"Buffer starting or buffer underrun
\n
"
);
/* recover mixing for all buffers */
recover
=
TRUE
;
/* reset mix position to write position */
device
->
mixpos
=
writepos
;
inq
=
0
;
maxq
=
device
->
buflen
;
if
(
maxq
>
frag
)
maxq
=
frag
;
FillMemory
(
device
->
buffer
,
device
->
buflen
,
nfiller
);
paused
=
TRUE
;
}
if
(
lock
)
IDsDriverBuffer_Lock
(
device
->
hwbuf
,
&
buf1
,
&
size1
,
&
buf2
,
&
size2
,
device
->
mixpos
,
maxq
,
0
);
/* do the mixing */
frag
=
DSOUND_MixToPrimary
(
device
,
playpos
,
writepos
,
maxq
,
paused
);
if
(
forced
)
frag
=
maxq
-
inq
;
device
->
mixpos
+=
frag
;
frag
=
DSOUND_MixToPrimary
(
device
,
playpos
,
writepos
,
maxq
,
recover
,
&
all_stopped
);
/* update the mix position, taking wrap-around into acount */
device
->
mixpos
=
writepos
+
frag
;
device
->
mixpos
%=
device
->
buflen
;
if
(
frag
)
{
/* buffers have been filled, restart playback */
if
(
device
->
state
==
STATE_STARTING
)
{
if
(
lock
)
{
DWORD
frag2
=
(
frag
>
size1
?
frag
-
size1
:
0
);
frag
-=
frag2
;
if
(
frag2
>
size2
)
{
FIXME
(
"Buffering too much! (%d, %d, %d, %d)
\n
"
,
maxq
,
frag
,
size2
,
frag2
-
size2
);
frag2
=
size2
;
}
IDsDriverBuffer_Unlock
(
device
->
hwbuf
,
buf1
,
frag
,
buf2
,
frag2
);
}
/* update prebuff left */
prebuff_left
=
DSOUND_BufPtrDiff
(
device
->
buflen
,
device
->
mixpos
,
playpos
);
/* check if have a whole fragment */
if
(
prebuff_left
>=
device
->
fraglen
){
/* update the wave queue if using wave system */
if
(
device
->
hwbuf
==
NULL
){
DSOUND_WaveQueue
(
device
,
TRUE
);
}
/* buffers are full. start playing if applicable */
if
(
device
->
state
==
STATE_STARTING
){
TRACE
(
"started primary buffer
\n
"
);
if
(
DSOUND_PrimaryPlay
(
device
)
!=
DS_OK
){
WARN
(
"DSOUND_PrimaryPlay failed
\n
"
);
}
else
{
/* we are playing now */
device
->
state
=
STATE_PLAYING
;
}
else
if
(
device
->
state
==
STATE_STOPPED
)
{
/* the dsound is supposed to play if there's something to play
* even if it is reported as stopped, so don't let this confuse you */
device
->
state
=
STATE_STOPPING
;
}
LeaveCriticalSection
(
&
(
device
->
mixlock
));
if
(
paused
)
{
if
(
DSOUND_PrimaryPlay
(
device
)
!=
DS_OK
)
/* buffers are full. start stopping if applicable */
if
(
device
->
state
==
STATE_STOPPED
){
TRACE
(
"restarting primary buffer"
);
if
(
DSOUND_PrimaryPlay
(
device
)
!=
DS_OK
){
WARN
(
"DSOUND_PrimaryPlay failed
\n
"
);
else
TRACE
(
"starting playback
\n
"
);
}
else
{
/* start stopping again. as soon as there is no more data, it will stop */
device
->
state
=
STATE_STOPPING
;
}
else
LeaveCriticalSection
(
&
(
device
->
mixlock
));
}
}
/* if device was stopping, its for sure stopped when all buffers have stopped */
else
if
((
all_stopped
==
TRUE
)
&&
(
device
->
state
==
STATE_STOPPING
)){
TRACE
(
"All buffers have stopped. Stopping primary buffer
\n
"
);
device
->
state
=
STATE_STOPPED
;
/* stop the primary buffer now */
DSOUND_PrimaryStop
(
device
);
}
}
else
{
/* update the wave queue if using wave system */
if
(
device
->
hwbuf
==
NULL
){
DSOUND_WaveQueue
(
device
,
TRUE
);
}
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
if
(
device
->
state
==
STATE_STARTING
)
{
if
(
DSOUND_PrimaryPlay
(
device
)
!=
DS_OK
)
...
...
@@ -1194,6 +968,9 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
device
->
state
=
STATE_STOPPED
;
}
}
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
}
void
CALLBACK
DSOUND_timer
(
UINT
timerID
,
UINT
msg
,
DWORD_PTR
dwUser
,
...
...
@@ -1230,39 +1007,29 @@ void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, D
TRACE
(
"entering at %d, msg=%08x(%s)
\n
"
,
GetTickCount
(),
msg
,
msg
==
MM_WOM_DONE
?
"MM_WOM_DONE"
:
msg
==
MM_WOM_CLOSE
?
"MM_WOM_CLOSE"
:
msg
==
MM_WOM_OPEN
?
"MM_WOM_OPEN"
:
"UNKNOWN"
);
/* check if packet completed from wave driver */
if
(
msg
==
MM_WOM_DONE
)
{
DWORD
inq
,
mixq
,
fraglen
,
buflen
,
pwplay
,
playpos
,
mixpos
;
if
(
device
->
pwqueue
==
(
DWORD
)
-
1
)
{
TRACE
(
"completed due to reset
\n
"
);
return
;
}
/* it could be a bad idea to enter critical section here... if there's lock contention,
* the resulting scheduling delays might obstruct the winmm player thread */
#ifdef SYNC_CALLBACK
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
#endif
/* retrieve current values */
fraglen
=
device
->
fraglen
;
buflen
=
device
->
buflen
;
pwplay
=
device
->
pwplay
;
playpos
=
pwplay
*
fraglen
;
mixpos
=
device
->
mixpos
;
/* check remaining mixed data */
inq
=
DSOUND_BufPtrDiff
(
buflen
,
mixpos
,
playpos
);
mixq
=
inq
/
fraglen
;
if
((
inq
-
(
mixq
*
fraglen
))
>
0
)
mixq
++
;
/* complete the playing buffer */
TRACE
(
"done playing primary pos=%d
\n
"
,
playpos
);
pwplay
++
;
if
(
pwplay
>=
DS_HEL_FRAGS
)
pwplay
=
0
;
/* write new values */
device
->
pwplay
=
pwplay
;
TRACE
(
"done playing primary pos=%d
\n
"
,
device
->
pwplay
*
device
->
fraglen
);
/* update playpos */
device
->
pwplay
++
;
device
->
pwplay
%=
DS_HEL_FRAGS
;
/* sanity */
if
(
device
->
pwqueue
==
0
){
ERR
(
"Wave queue corrupted!
\n
"
);
}
/* update queue */
device
->
pwqueue
--
;
/* queue new buffer if we have data for it */
if
(
inq
>
1
)
DSOUND_WaveQueue
(
device
,
inq
-
1
);
#ifdef SYNC_CALLBACK
LeaveCriticalSection
(
&
(
device
->
mixlock
));
#endif
/* **** */
}
TRACE
(
"completed
\n
"
);
}
dlls/dsound/primary.c
View file @
a7d6ed8e
...
...
@@ -82,12 +82,14 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
waveOutPause
(
device
->
hwo
);
if
(
device
->
state
==
STATE_PLAYING
)
device
->
state
=
STATE_STARTING
;
else
if
(
device
->
state
==
STATE_STOPPING
)
device
->
state
=
STATE_STOPPED
;
/* use fragments of 10ms (1/100s) each (which should get us within
* the documented write cursor lead of 10-15ms) */
buflen
=
((
device
->
pwfx
->
nSamplesPerSec
/
100
)
*
device
->
pwfx
->
nBlockAlign
)
*
DS_HEL_FRAGS
;
/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
on windows this size is always fixed (tested on win-xp) */
buflen
=
DS_HEL_BUFLEN
;
TRACE
(
"desired buflen=%d, old buffer=%p
\n
"
,
buflen
,
device
->
buffer
);
/* reallocate emulated primary buffer */
/* reallocate emulated primary buffer */
if
(
device
->
buffer
)
newbuf
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
device
->
buffer
,
buflen
);
else
...
...
@@ -106,6 +108,11 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
device
->
fraglen
=
device
->
buflen
/
DS_HEL_FRAGS
;
/* sanity */
if
(
device
->
buflen
%
DS_HEL_FRAGS
){
ERR
(
"Bad DS_HEL_FRAGS resolution
\n
"
);
}
/* prepare fragment headers */
for
(
c
=
0
;
c
<
DS_HEL_FRAGS
;
c
++
)
{
device
->
pwave
[
c
]
->
lpData
=
(
char
*
)
device
->
buffer
+
c
*
device
->
fraglen
;
...
...
@@ -128,7 +135,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
device
->
mixpos
=
0
;
FillMemory
(
device
->
buffer
,
device
->
buflen
,
(
device
->
pwfx
->
wBitsPerSample
==
8
)
?
128
:
0
);
TRACE
(
"fraglen=%d
\n
"
,
device
->
fraglen
);
DSOUND_WaveQueue
(
device
,
(
DWORD
)
-
1
);
}
if
((
err
==
DS_OK
)
&&
(
merr
!=
DS_OK
))
err
=
merr
;
...
...
@@ -161,10 +167,17 @@ static void DSOUND_PrimaryClose(DirectSoundDevice *device)
if
(
!
device
->
hwbuf
)
{
unsigned
c
;
/* get out of CS when calling the wave system */
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
device
->
pwqueue
=
(
DWORD
)
-
1
;
/* resetting queues */
waveOutReset
(
device
->
hwo
);
for
(
c
=
0
;
c
<
DS_HEL_FRAGS
;
c
++
)
waveOutUnprepareHeader
(
device
->
hwo
,
device
->
pwave
[
c
],
sizeof
(
WAVEHDR
));
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
/* clear the queue */
device
->
pwqueue
=
0
;
}
else
{
if
(
IDsDriverBuffer_Release
(
device
->
hwbuf
)
==
0
)
...
...
@@ -224,6 +237,7 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
{
TRACE
(
"(%p)
\n
"
,
device
);
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
DSOUND_PrimaryClose
(
device
);
...
...
@@ -240,7 +254,10 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
}
HeapFree
(
GetProcessHeap
(),
0
,
device
->
pwfx
);
device
->
pwfx
=
NULL
;
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
return
DS_OK
;
}
...
...
@@ -267,7 +284,6 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
HRESULT
err
=
DS_OK
;
TRACE
(
"(%p)
\n
"
,
device
);
EnterCriticalSection
(
&
(
device
->
mixlock
));
if
(
device
->
hwbuf
)
{
err
=
IDsDriverBuffer_Stop
(
device
->
hwbuf
);
if
(
err
==
DSERR_BUFFERLOST
)
{
...
...
@@ -296,11 +312,20 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
WARN
(
"IDsDriverBuffer_Stop failed
\n
"
);
}
}
else
{
/* dont call the wave system with the lock set */
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
err
=
mmErr
(
waveOutPause
(
device
->
hwo
));
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
if
(
err
!=
DS_OK
)
WARN
(
"waveOutPause failed
\n
"
);
}
LeaveCriticalSection
(
&
(
device
->
mixlock
));
return
err
;
}
...
...
@@ -315,19 +340,20 @@ HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LP
return
err
;
}
}
else
{
/* check if playpos was requested */
if
(
playpos
)
{
MMTIME
mtime
;
mtime
.
wType
=
TIME_BYTES
;
waveOutGetPosition
(
device
->
hwo
,
&
mtime
,
sizeof
(
mtime
));
mtime
.
u
.
cb
=
mtime
.
u
.
cb
%
device
->
buflen
;
*
playpos
=
mtime
.
u
.
cb
;
/* use the cached play position */
*
playpos
=
device
->
pwplay
*
device
->
fraglen
;
}
/* check if writepos was requested */
if
(
writepos
)
{
/* the writepos should only be used by apps with WRITEPRIMARY priority,
* in which case our software mixer is disabled anyway */
*
writepos
=
(
device
->
pwplay
+
ds_hel_margin
)
*
device
->
fraglen
;
while
(
*
writepos
>=
device
->
buflen
)
*
writepos
-
=
device
->
buflen
;
TRACE
(
"pwplay=%i, pwqueue=%i
\n
"
,
device
->
pwplay
,
device
->
pwqueue
);
/* the writepos is the first non-queued position */
*
writepos
=
(
device
->
pwplay
+
device
->
pwqueue
)
*
device
->
fraglen
;
*
writepos
%
=
device
->
buflen
;
}
}
TRACE
(
"playpos = %d, writepos = %d (%p, time=%d)
\n
"
,
playpos
?*
playpos
:
0
,
writepos
?*
writepos
:
0
,
device
,
GetTickCount
());
...
...
@@ -607,6 +633,9 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
DirectSoundDevice
*
device
=
((
PrimaryBufferImpl
*
)
iface
)
->
device
;
TRACE
(
"(%p,%p,%p)
\n
"
,
iface
,
playpos
,
writepos
);
/* **** */
EnterCriticalSection
(
&
(
device
->
mixlock
));
hres
=
DSOUND_PrimaryGetPosition
(
device
,
playpos
,
writepos
);
if
(
hres
!=
DS_OK
)
{
WARN
(
"DSOUND_PrimaryGetPosition failed
\n
"
);
...
...
@@ -618,6 +647,10 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
*
writepos
+=
device
->
writelead
;
while
(
*
writepos
>=
device
->
buflen
)
*
writepos
-=
device
->
buflen
;
}
LeaveCriticalSection
(
&
(
device
->
mixlock
));
/* **** */
TRACE
(
"playpos = %d, writepos = %d (%p, time=%d)
\n
"
,
playpos
?*
playpos
:
0
,
writepos
?*
writepos
:
0
,
device
,
GetTickCount
());
return
DS_OK
;
}
...
...
dlls/dsound/sound3d.c
View file @
a7d6ed8e
...
...
@@ -192,7 +192,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
TRACE
(
"3D processing disabled
\n
"
);
/* this one is here only to eliminate annoying warning message */
DSOUND_RecalcVolPan
(
&
dsb
->
volpan
);
DSOUND_ForceRemix
(
dsb
);
break
;
case
DS3DMODE_NORMAL
:
TRACE
(
"Normal 3D processing mode
\n
"
);
...
...
@@ -319,7 +318,6 @@ static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb)
TRACE
(
"(%p)
\n
"
,
dsb
);
DSOUND_Calc3DBuffer
(
dsb
);
DSOUND_ForceRemix
(
dsb
);
}
static
void
DSOUND_ChangeListener
(
IDirectSound3DListenerImpl
*
ds3dl
)
...
...
@@ -332,6 +330,8 @@ static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
crash without the following line) */
if
(
ds3dl
->
device
->
buffers
[
i
]
->
ds3db
==
NULL
)
continue
;
/* check if this buffer is waiting for recalculation */
if
(
ds3dl
->
device
->
buffers
[
i
]
->
ds3db_need_recalc
)
{
DSOUND_Mix3DBuffer
(
ds3dl
->
device
->
buffers
[
i
]);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment