strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[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 void put8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
120 {
121     BYTE* buf = dsb->device->tmp_buffer;
122     buf += pos + channel;
123     if(value <= -1.f)
124         *buf = 0;
125     else if(value >= 1.f * 0x7F / 0x80)
126         *buf = 0xFF;
127     else
128         *buf = lrintf((value + 1.f) * 0x80);
129 }
130
131 static void put16(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
132 {
133     BYTE* buf = dsb->device->tmp_buffer;
134     SHORT *sbuf = (SHORT*)(buf + pos + 2 * channel);
135     if(value <= -1.f)
136         *sbuf = 0x8000;
137     else if(value >= 1.f * 0x7FFF / 0x8000)
138         *sbuf = 0x7FFF;
139     else
140         *sbuf = le16(lrintf(value * 0x8000));
141 }
142
143 static void put24(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
144 {
145     BYTE* buf = dsb->device->tmp_buffer;
146     LONG t;
147     buf += pos + 3 * channel;
148     if(value <= -1.f)
149         t = 0x80000000;
150     else if(value >= 1.f * 0x7FFFFF / 0x800000)
151         t = 0x7FFFFF00;
152     else
153         t = lrintf(value * 0x80000000U);
154     buf[0] = (t >> 8) & 0xFF;
155     buf[1] = (t >> 16) & 0xFF;
156     buf[2] = (t >> 24) & 0xFF;
157 }
158
159 static void put32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
160 {
161     BYTE* buf = dsb->device->tmp_buffer;
162     LONG *sbuf = (LONG*)(buf + pos + 4 * channel);
163     if(value <= -1.f)
164         *sbuf = 0x80000000;
165     else if(value >= 1.f * 0x7FFFFFFF / 0x80000000U)  /* this rounds to 1.f */
166         *sbuf = 0x7FFFFFFF;
167     else
168         *sbuf = le32(lrintf(value * 0x80000000U));
169 }
170
171 const bitsputfunc putbpp[4] = {put8, put16, put24, put32};
172
173 void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
174 {
175     dsb->put_aux(dsb, pos, 0, value);
176     dsb->put_aux(dsb, pos, 1, value);
177 }
178
179 static void mix8(signed char *src, INT *dst, unsigned len)
180 {
181     TRACE("%p - %p %d\n", src, dst, len);
182     while (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);
185 }
186
187 static void mix16(SHORT *src, INT *dst, unsigned len)
188 {
189     TRACE("%p - %p %d\n", src, dst, len);
190     len /= 2;
191     while (len--)
192     {
193         *dst += le16(*src);
194         ++dst; ++src;
195     }
196 }
197
198 static void mix24(BYTE *src, INT *dst, unsigned len)
199 {
200     TRACE("%p - %p %d\n", src, dst, len);
201     len /= 3;
202     while (len--)
203     {
204         DWORD field;
205         field = ((DWORD)src[2] << 16) + ((DWORD)src[1] << 8) + (DWORD)src[0];
206         if (src[2] & 0x80)
207             field |= 0xFF000000U;
208         *(dst++) += field;
209         src += 3;
210     }
211 }
212
213 static void mix32(INT *src, LONGLONG *dst, unsigned len)
214 {
215     TRACE("%p - %p %d\n", src, dst, len);
216     len /= 4;
217     while (len--)
218         *(dst++) += le32(*(src++));
219 }
220
221 const mixfunc mixfunctions[4] = {
222     (mixfunc)mix8,
223     (mixfunc)mix16,
224     (mixfunc)mix24,
225     (mixfunc)mix32
226 };
227
228 static void norm8(INT *src, signed char *dst, unsigned len)
229 {
230     TRACE("%p - %p %d\n", src, dst, len);
231     while (len--)
232     {
233         *dst = (*src) + 0x80;
234         if (*src < -0x80)
235             *dst = 0;
236         else if (*src > 0x7f)
237             *dst = 0xff;
238         ++dst;
239         ++src;
240     }
241 }
242
243 static void norm16(INT *src, SHORT *dst, unsigned len)
244 {
245     TRACE("%p - %p %d\n", src, dst, len);
246     len /= 2;
247     while (len--)
248     {
249         *dst = le16(*src);
250         if (*src <= -0x8000)
251             *dst = le16(0x8000);
252         else if (*src > 0x7fff)
253             *dst = le16(0x7fff);
254         ++dst;
255         ++src;
256     }
257 }
258
259 static void norm24(INT *src, BYTE *dst, unsigned len)
260 {
261     TRACE("%p - %p %d\n", src, dst, len);
262     len /= 3;
263     while (len--)
264     {
265         if (*src <= -0x800000)
266         {
267             dst[0] = 0;
268             dst[1] = 0;
269             dst[2] = 0x80;
270         }
271         else if (*src > 0x7fffff)
272         {
273             dst[0] = 0xff;
274             dst[1] = 0xff;
275             dst[2] = 0x7f;
276         }
277         else
278         {
279             dst[0] = *src;
280             dst[1] = *src >> 8;
281             dst[2] = *src >> 16;
282         }
283         dst += 3;
284         ++src;
285     }
286 }
287
288 static void norm32(LONGLONG *src, INT *dst, unsigned len)
289 {
290     TRACE("%p - %p %d\n", src, dst, len);
291     len /= 4;
292     while (len--)
293     {
294         *dst = le32(*src);
295         if (*src <= -(LONGLONG)0x80000000)
296             *dst = le32(0x80000000);
297         else if (*src > 0x7fffffff)
298             *dst = le32(0x7fffffff);
299         ++dst;
300         ++src;
301     }
302 }
303
304 const normfunc normfunctions[4] = {
305     (normfunc)norm8,
306     (normfunc)norm16,
307     (normfunc)norm24,
308     (normfunc)norm32,
309 };