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 inline unsigned char f_to_8(float value)
123 if(value >= 1.f * 0x7f / 0x80)
125 return lrintf((value + 1.f) * 0x80);
128 static inline SHORT f_to_16(float value)
132 if(value >= 1.f * 0x7FFF / 0x8000)
134 return le16(lrintf(value * 0x8000));
137 static LONG f_to_24(float value)
141 if(value >= 1.f * 0x7FFFFF / 0x800000)
143 return lrintf(value * 0x80000000U);
146 static inline LONG f_to_32(float value)
150 if(value >= 1.f * 0x7FFFFFFF / 0x80000000U) /* this rounds to 1.f */
152 return le32(lrintf(value * 0x80000000U));
155 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
157 BYTE *buf = (BYTE *)dsb->device->tmp_buffer;
158 float *fbuf = (float*)(buf + pos + sizeof(float) * channel);
162 void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
164 dsb->put_aux(dsb, pos, 0, value);
165 dsb->put_aux(dsb, pos, 1, value);
168 void mixieee32(float *src, float *dst, unsigned samples)
170 TRACE("%p - %p %d\n", src, dst, samples);
172 *(dst++) += *(src++);
175 static void norm8(float *src, unsigned char *dst, unsigned len)
177 TRACE("%p - %p %d\n", src, dst, len);
186 static void norm16(float *src, SHORT *dst, unsigned len)
188 TRACE("%p - %p %d\n", src, dst, len);
192 *dst = f_to_16(*src);
198 static void norm24(float *src, BYTE *dst, unsigned len)
200 TRACE("%p - %p %d\n", src, dst, len);
204 LONG t = f_to_24(*src);
205 dst[0] = (t >> 8) & 0xFF;
206 dst[1] = (t >> 16) & 0xFF;
213 static void norm32(float *src, INT *dst, unsigned len)
215 TRACE("%p - %p %d\n", src, dst, len);
219 *dst = f_to_32(*src);
225 static void normieee32(float *src, float *dst, unsigned len)
227 TRACE("%p - %p %d\n", src, dst, len);
242 const normfunc normfunctions[5] = {