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
44 #include "wine/debug.h"
46 #include "dsound_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
50 #ifdef WORDS_BIGENDIAN
51 #define le16(x) RtlUshortByteSwap((x))
52 #define le32(x) RtlUlongByteSwap((x))
58 static float get8(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
60 const BYTE
* buf
= dsb
->buffer
->memory
;
62 return (buf
[0] - 0x80) / (float)0x80;
65 static float get16(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
67 const BYTE
* buf
= dsb
->buffer
->memory
;
68 const SHORT
*sbuf
= (const SHORT
*)(buf
+ pos
+ 2 * channel
);
69 SHORT sample
= (SHORT
)le16(*sbuf
);
70 return sample
/ (float)0x8000;
73 static float get24(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
76 const BYTE
* buf
= dsb
->buffer
->memory
;
77 buf
+= pos
+ 3 * channel
;
78 /* The next expression deliberately has an overflow for buf[2] >= 0x80,
79 this is how negative values are made.
81 sample
= (buf
[0] << 8) | (buf
[1] << 16) | (buf
[2] << 24);
82 return sample
/ (float)0x80000000U
;
85 static float get32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
87 const BYTE
* buf
= dsb
->buffer
->memory
;
88 const LONG
*sbuf
= (const LONG
*)(buf
+ pos
+ 4 * channel
);
89 LONG sample
= le32(*sbuf
);
90 return sample
/ (float)0x80000000U
;
93 static float getieee32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
95 const BYTE
* buf
= dsb
->buffer
->memory
;
96 const float *sbuf
= (const float*)(buf
+ pos
+ 4 * channel
);
97 /* The value will be clipped later, when put into some non-float buffer */
101 const bitsgetfunc getbpp
[5] = {get8
, get16
, get24
, get32
, getieee32
};
103 float get_mono(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
)
105 DWORD channels
= dsb
->pwfx
->nChannels
;
108 /* XXX: does Windows include LFE into the mix? */
109 for (c
= 0; c
< channels
; c
++)
110 val
+= dsb
->get_aux(dsb
, pos
, c
);
115 static inline unsigned char f_to_8(float value
)
119 if(value
>= 1.f
* 0x7f / 0x80)
121 return lrintf((value
+ 1.f
) * 0x80);
124 static inline SHORT
f_to_16(float value
)
128 if(value
>= 1.f
* 0x7FFF / 0x8000)
130 return le16(lrintf(value
* 0x8000));
133 static LONG
f_to_24(float value
)
137 if(value
>= 1.f
* 0x7FFFFF / 0x800000)
139 return lrintf(value
* 0x80000000U
);
142 static inline LONG
f_to_32(float value
)
146 if(value
>= 1.f
* 0x7FFFFFFF / 0x80000000U
) /* this rounds to 1.f */
148 return le32(lrintf(value
* 0x80000000U
));
151 void putieee32(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
153 BYTE
*buf
= (BYTE
*)dsb
->device
->tmp_buffer
;
154 float *fbuf
= (float*)(buf
+ pos
+ sizeof(float) * channel
);
158 void putieee32_sum(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
160 BYTE
*buf
= (BYTE
*)dsb
->device
->tmp_buffer
;
161 float *fbuf
= (float*)(buf
+ pos
+ sizeof(float) * channel
);
165 void put_mono2stereo(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
167 dsb
->put_aux(dsb
, pos
, 0, value
);
168 dsb
->put_aux(dsb
, pos
, 1, value
);
171 void put_mono2quad(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
173 dsb
->put_aux(dsb
, pos
, 0, value
);
174 dsb
->put_aux(dsb
, pos
, 1, value
);
175 dsb
->put_aux(dsb
, pos
, 2, value
);
176 dsb
->put_aux(dsb
, pos
, 3, value
);
179 void put_stereo2quad(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
181 if (channel
== 0) { /* Left */
182 dsb
->put_aux(dsb
, pos
, 0, value
); /* Front left */
183 dsb
->put_aux(dsb
, pos
, 2, value
); /* Back left */
184 } else if (channel
== 1) { /* Right */
185 dsb
->put_aux(dsb
, pos
, 1, value
); /* Front right */
186 dsb
->put_aux(dsb
, pos
, 3, value
); /* Back right */
190 void put_mono2surround51(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
192 dsb
->put_aux(dsb
, pos
, 0, value
);
193 dsb
->put_aux(dsb
, pos
, 1, value
);
194 dsb
->put_aux(dsb
, pos
, 2, value
);
195 dsb
->put_aux(dsb
, pos
, 3, value
);
196 dsb
->put_aux(dsb
, pos
, 4, value
);
197 dsb
->put_aux(dsb
, pos
, 5, value
);
200 void put_stereo2surround51(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
202 if (channel
== 0) { /* Left */
203 dsb
->put_aux(dsb
, pos
, 0, value
); /* Front left */
204 dsb
->put_aux(dsb
, pos
, 4, value
); /* Back left */
206 dsb
->put_aux(dsb
, pos
, 2, 0.0f
); /* Mute front centre */
207 dsb
->put_aux(dsb
, pos
, 3, 0.0f
); /* Mute LFE */
208 } else if (channel
== 1) { /* Right */
209 dsb
->put_aux(dsb
, pos
, 1, value
); /* Front right */
210 dsb
->put_aux(dsb
, pos
, 5, value
); /* Back right */
214 void put_surround512stereo(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
216 /* based on analyzing a recording of a dsound downmix */
219 case 4: /* surround left */
221 dsb
->put_aux(dsb
, pos
, 0, value
);
224 case 0: /* front left */
226 dsb
->put_aux(dsb
, pos
, 0, value
);
229 case 5: /* surround right */
231 dsb
->put_aux(dsb
, pos
, 1, value
);
234 case 1: /* front right */
236 dsb
->put_aux(dsb
, pos
, 1, value
);
241 dsb
->put_aux(dsb
, pos
, 0, value
);
242 dsb
->put_aux(dsb
, pos
, 1, value
);
246 /* LFE is totally ignored in dsound when downmixing to 2 channels */
251 void put_surround712stereo(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
253 /* based on analyzing a recording of a dsound downmix */
256 case 6: /* back left */
258 dsb
->put_aux(dsb
, pos
, 0, value
);
261 case 4: /* surround left */
263 dsb
->put_aux(dsb
, pos
, 0, value
);
266 case 0: /* front left */
268 dsb
->put_aux(dsb
, pos
, 0, value
);
271 case 7: /* back right */
273 dsb
->put_aux(dsb
, pos
, 1, value
);
276 case 5: /* surround right */
278 dsb
->put_aux(dsb
, pos
, 1, value
);
281 case 1: /* front right */
283 dsb
->put_aux(dsb
, pos
, 1, value
);
288 dsb
->put_aux(dsb
, pos
, 0, value
);
289 dsb
->put_aux(dsb
, pos
, 1, value
);
293 /* LFE is totally ignored in dsound when downmixing to 2 channels */
298 void put_quad2stereo(const IDirectSoundBufferImpl
*dsb
, DWORD pos
, DWORD channel
, float value
)
300 /* based on pulseaudio's downmix algorithm */
303 case 2: /* back left */
304 value
*= 0.1f
; /* (1/9) / (sum of left volumes) */
305 dsb
->put_aux(dsb
, pos
, 0, value
);
308 case 0: /* front left */
309 value
*= 0.9f
; /* 1 / (sum of left volumes) */
310 dsb
->put_aux(dsb
, pos
, 0, value
);
313 case 3: /* back right */
314 value
*= 0.1f
; /* (1/9) / (sum of right volumes) */
315 dsb
->put_aux(dsb
, pos
, 1, value
);
318 case 1: /* front right */
319 value
*= 0.9f
; /* 1 / (sum of right volumes) */
320 dsb
->put_aux(dsb
, pos
, 1, value
);
325 void mixieee32(float *src
, float *dst
, unsigned samples
)
327 TRACE("%p - %p %d\n", src
, dst
, samples
);
329 *(dst
++) += *(src
++);
332 static void norm8(float *src
, unsigned char *dst
, unsigned samples
)
334 TRACE("%p - %p %d\n", src
, dst
, samples
);
343 static void norm16(float *src
, SHORT
*dst
, unsigned samples
)
345 TRACE("%p - %p %d\n", src
, dst
, samples
);
348 *dst
= f_to_16(*src
);
354 static void norm24(float *src
, BYTE
*dst
, unsigned samples
)
356 TRACE("%p - %p %d\n", src
, dst
, samples
);
359 LONG t
= f_to_24(*src
);
360 dst
[0] = (t
>> 8) & 0xFF;
361 dst
[1] = (t
>> 16) & 0xFF;
368 static void norm32(float *src
, INT
*dst
, unsigned samples
)
370 TRACE("%p - %p %d\n", src
, dst
, samples
);
373 *dst
= f_to_32(*src
);
379 const normfunc normfunctions
[4] = {