1 /* DirectSound format conversion and mixing routines
3 * Copyright 2007 Maarten Lankhorst
4 * Copyright 2011 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 /* 8 bits is unsigned, the rest is signed.
22 * First I tried to reuse existing stuff from alsa-lib, after that
23 * didn't work, I gave up and just went for individual hacks.
25 * 24 bit is expensive to do, due to unaligned access.
26 * In dlls/winex11.drv/dib_convert.c convert_888_to_0888_asis there is a way
27 * around it, but I'm happy current code works, maybe something for later.
29 * The ^ 0x80 flips the signed bit, this is the conversion from
30 * signed (-128.. 0.. 127) to unsigned (0...255)
31 * This is only temporary: All 8 bit data should be converted to signed.
32 * then when fed to the sound card, it should be converted to unsigned again.
34 * Sound is LITTLE endian
42 #define NONAMELESSSTRUCT
43 #define NONAMELESSUNION
48 #include "wine/debug.h"
50 #include "dsound_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
54 #ifdef WORDS_BIGENDIAN
55 #define le16(x) RtlUshortByteSwap((x))
56 #define le32(x) RtlUlongByteSwap((x))
62 static float get8(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
64 const BYTE
* buf
= dsb
->buffer
->memory
;
66 return (buf
[0] - 0x80) / (float)0x80;
69 static float get16(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
71 const BYTE
* buf
= dsb
->buffer
->memory
;
72 const SHORT
*sbuf
= (const SHORT
*)(buf
+ pos
+ 2 * channel
);
73 SHORT sample
= (SHORT
)le16(*sbuf
);
74 return sample
/ (float)0x8000;
77 static float get24(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
80 const BYTE
* buf
= dsb
->buffer
->memory
;
81 buf
+= pos
+ 3 * channel
;
82 /* The next expression deliberately has an overflow for buf[2] >= 0x80,
83 this is how negative values are made.
85 sample
= (buf
[0] << 8) | (buf
[1] << 16) | (buf
[2] << 24);
86 return sample
/ (float)0x80000000U
;
89 static float get32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
91 const BYTE
* buf
= dsb
->buffer
->memory
;
92 const LONG
*sbuf
= (const LONG
*)(buf
+ pos
+ 4 * channel
);
93 LONG sample
= le32(*sbuf
);
94 return sample
/ (float)0x80000000U
;
97 static float getieee32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
99 const BYTE
* buf
= dsb
->buffer
->memory
;
100 const float *sbuf
= (const float*)(buf
+ pos
+ 4 * channel
);
101 /* The value will be clipped later, when put into some non-float buffer */
105 const bitsgetfunc getbpp
[5] = {get8
, get16
, get24
, get32
, getieee32
};
107 float get_mono(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
109 DWORD channels
= dsb
->pwfx
->nChannels
;
112 /* XXX: does Windows include LFE into the mix? */
113 for (c
= 0; c
< channels
; c
++)
114 val
+= dsb
->get_aux(dsb
, pos
, c
);
119 static void put8(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
121 BYTE
* buf
= dsb
->device
->tmp_buffer
;
122 buf
+= pos
+ channel
;
125 else if(value
>= 1.f
* 0x7F / 0x80)
128 *buf
= lrintf((value
+ 1.f
) * 0x80);
131 static void put16(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
133 BYTE
* buf
= dsb
->device
->tmp_buffer
;
134 SHORT
*sbuf
= (SHORT
*)(buf
+ pos
+ 2 * channel
);
137 else if(value
>= 1.f
* 0x7FFF / 0x8000)
140 *sbuf
= le16(lrintf(value
* 0x8000));
143 static void put24(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
145 BYTE
* buf
= dsb
->device
->tmp_buffer
;
147 buf
+= pos
+ 3 * channel
;
150 else if(value
>= 1.f
* 0x7FFFFF / 0x800000)
153 t
= lrintf(value
* 0x80000000U
);
154 buf
[0] = (t
>> 8) & 0xFF;
155 buf
[1] = (t
>> 16) & 0xFF;
156 buf
[2] = (t
>> 24) & 0xFF;
159 static void put32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
161 BYTE
* buf
= dsb
->device
->tmp_buffer
;
162 LONG
*sbuf
= (LONG
*)(buf
+ pos
+ 4 * channel
);
165 else if(value
>= 1.f
* 0x7FFFFFFF / 0x80000000U
) /* this rounds to 1.f */
168 *sbuf
= le32(lrintf(value
* 0x80000000U
));
171 const bitsputfunc putbpp
[4] = {put8
, put16
, put24
, put32
};
173 void put_mono2stereo(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
175 dsb
->put_aux(dsb
, pos
, 0, value
);
176 dsb
->put_aux(dsb
, pos
, 1, value
);
179 static void mix8(signed char *src
, INT
*dst
, unsigned len
)
181 TRACE("%p - %p %d\n", src
, dst
, len
);
183 /* 8-bit WAV is unsigned, it's here converted to signed, normalize function will convert it back again */
184 *(dst
++) += (signed char)((BYTE
)*(src
++) - (BYTE
)0x80);
187 static void mix16(SHORT
*src
, INT
*dst
, unsigned len
)
189 TRACE("%p - %p %d\n", src
, dst
, len
);
198 static void mix24(BYTE
*src
, INT
*dst
, unsigned len
)
200 TRACE("%p - %p %d\n", src
, dst
, len
);
205 field
= ((DWORD
)src
[2] << 16) + ((DWORD
)src
[1] << 8) + (DWORD
)src
[0];
207 field
|= 0xFF000000U
;
213 static void mix32(INT
*src
, LONGLONG
*dst
, unsigned len
)
215 TRACE("%p - %p %d\n", src
, dst
, len
);
218 *(dst
++) += le32(*(src
++));
221 const mixfunc mixfunctions
[4] = {
228 static void norm8(INT
*src
, signed char *dst
, unsigned len
)
230 TRACE("%p - %p %d\n", src
, dst
, len
);
233 *dst
= (*src
) + 0x80;
236 else if (*src
> 0x7f)
243 static void norm16(INT
*src
, SHORT
*dst
, unsigned len
)
245 TRACE("%p - %p %d\n", src
, dst
, len
);
252 else if (*src
> 0x7fff)
259 static void norm24(INT
*src
, BYTE
*dst
, unsigned len
)
261 TRACE("%p - %p %d\n", src
, dst
, len
);
265 if (*src
<= -0x800000)
271 else if (*src
> 0x7fffff)
288 static void norm32(LONGLONG
*src
, INT
*dst
, unsigned len
)
290 TRACE("%p - %p %d\n", src
, dst
, len
);
295 if (*src
<= -(LONGLONG
)0x80000000)
296 *dst
= le32(0x80000000);
297 else if (*src
> 0x7fffffff)
298 *dst
= le32(0x7fffffff);
304 const normfunc normfunctions
[4] = {