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] = {