msvcp60: Avoid signed-unsigned integer comparisons.
[wine] / dlls / dsound / dsound_convert.c
1 /* DirectSound format conversion and mixing routines
2  *
3  * Copyright 2007 Maarten Lankhorst
4  * Copyright 2011 Owen Rudge for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20
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.
24  *
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.
28  *
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.
33  *
34  * Sound is LITTLE endian
35  */
36
37 #include "config.h"
38
39 #include <stdarg.h>
40 #include <math.h>
41
42 #define NONAMELESSSTRUCT
43 #define NONAMELESSUNION
44 #include "windef.h"
45 #include "winbase.h"
46 #include "mmsystem.h"
47 #include "winternl.h"
48 #include "wine/debug.h"
49 #include "dsound.h"
50 #include "dsound_private.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
53
54 #ifdef WORDS_BIGENDIAN
55 #define le16(x) RtlUshortByteSwap((x))
56 #define le32(x) RtlUlongByteSwap((x))
57 #else
58 #define le16(x) (x)
59 #define le32(x) (x)
60 #endif
61
62 static float get8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
63 {
64     const BYTE* buf = dsb->buffer->memory;
65     buf += pos + channel;
66     return (buf[0] - 0x80) / (float)0x80;
67 }
68
69 static float get16(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
70 {
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;
75 }
76
77 static float get24(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
78 {
79     LONG sample;
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.
84      */
85     sample = (buf[0] << 8) | (buf[1] << 16) | (buf[2] << 24);
86     return sample / (float)0x80000000U;
87 }
88
89 static float get32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
90 {
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;
95 }
96
97 static float getieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
98 {
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 */
102     return *sbuf;
103 }
104
105 const bitsgetfunc getbpp[5] = {get8, get16, get24, get32, getieee32};
106
107 float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
108 {
109     DWORD channels = dsb->pwfx->nChannels;
110     DWORD c;
111     float val = 0;
112     /* XXX: does Windows include LFE into the mix? */
113     for (c = 0; c < channels; c++)
114         val += dsb->get_aux(dsb, pos, c);
115     val /= channels;
116     return val;
117 }
118
119 static inline unsigned char f_to_8(float value)
120 {
121     if(value <= -1.f)
122         return 0;
123     if(value >= 1.f * 0x7f / 0x80)
124         return 0xFF;
125     return lrintf((value + 1.f) * 0x80);
126 }
127
128 static inline SHORT f_to_16(float value)
129 {
130     if(value <= -1.f)
131         return 0x8000;
132     if(value >= 1.f * 0x7FFF / 0x8000)
133         return 0x7FFF;
134     return le16(lrintf(value * 0x8000));
135 }
136
137 static LONG f_to_24(float value)
138 {
139     if(value <= -1.f)
140         return 0x80000000;
141     if(value >= 1.f * 0x7FFFFF / 0x800000)
142         return 0x7FFFFF00;
143     return lrintf(value * 0x80000000U);
144 }
145
146 static inline LONG f_to_32(float value)
147 {
148     if(value <= -1.f)
149         return 0x80000000;
150     if(value >= 1.f * 0x7FFFFFFF / 0x80000000U)  /* this rounds to 1.f */
151         return 0x7FFFFFFF;
152     return le32(lrintf(value * 0x80000000U));
153 }
154
155 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
156 {
157     BYTE *buf = (BYTE *)dsb->device->tmp_buffer;
158     float *fbuf = (float*)(buf + pos + sizeof(float) * channel);
159     *fbuf = value;
160 }
161
162 void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
163 {
164     dsb->put_aux(dsb, pos, 0, value);
165     dsb->put_aux(dsb, pos, 1, value);
166 }
167
168 void mixieee32(float *src, float *dst, unsigned samples)
169 {
170     TRACE("%p - %p %d\n", src, dst, samples);
171     while (samples--)
172         *(dst++) += *(src++);
173 }
174
175 static void norm8(float *src, unsigned char *dst, unsigned len)
176 {
177     TRACE("%p - %p %d\n", src, dst, len);
178     while (len--)
179     {
180         *dst = f_to_8(*src);
181         ++dst;
182         ++src;
183     }
184 }
185
186 static void norm16(float *src, SHORT *dst, unsigned len)
187 {
188     TRACE("%p - %p %d\n", src, dst, len);
189     len /= 2;
190     while (len--)
191     {
192         *dst = f_to_16(*src);
193         ++dst;
194         ++src;
195     }
196 }
197
198 static void norm24(float *src, BYTE *dst, unsigned len)
199 {
200     TRACE("%p - %p %d\n", src, dst, len);
201     len /= 3;
202     while (len--)
203     {
204         LONG t = f_to_24(*src);
205         dst[0] = (t >> 8) & 0xFF;
206         dst[1] = (t >> 16) & 0xFF;
207         dst[2] = t >> 24;
208         dst += 3;
209         ++src;
210     }
211 }
212
213 static void norm32(float *src, INT *dst, unsigned len)
214 {
215     TRACE("%p - %p %d\n", src, dst, len);
216     len /= 4;
217     while (len--)
218     {
219         *dst = f_to_32(*src);
220         ++dst;
221         ++src;
222     }
223 }
224
225 static void normieee32(float *src, float *dst, unsigned len)
226 {
227     TRACE("%p - %p %d\n", src, dst, len);
228     len /= 4;
229     while (len--)
230     {
231         if(*src > 1)
232             *dst = 1;
233         else if(*src < -1)
234             *dst = -1;
235         else
236             *dst = *src;
237         ++dst;
238         ++src;
239     }
240 }
241
242 const normfunc normfunctions[5] = {
243     (normfunc)norm8,
244     (normfunc)norm16,
245     (normfunc)norm24,
246     (normfunc)norm32,
247     (normfunc)normieee32
248 };