mfplat: Implement GetContiguousLength() for d3d11 buffer.
[wine/zf.git] / dlls / dsound / dsound_convert.c
blob4735178a9a8d0642e54681dd6108e528553c5ab8
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
38 #include <stdarg.h>
39 #include <math.h>
41 #include "windef.h"
42 #include "winbase.h"
43 #include "mmsystem.h"
44 #include "wine/debug.h"
45 #include "dsound.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))
53 #else
54 #define le16(x) (x)
55 #define le32(x) (x)
56 #endif
58 static float get8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
60 const BYTE* buf = dsb->buffer->memory;
61 buf += pos + channel;
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)
75 LONG sample;
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 */
98 return *sbuf;
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;
106 DWORD c;
107 float val = 0;
108 /* XXX: does Windows include LFE into the mix? */
109 for (c = 0; c < channels; c++)
110 val += dsb->get_aux(dsb, pos, c);
111 val /= channels;
112 return val;
115 static inline unsigned char f_to_8(float value)
117 if(value <= -1.f)
118 return 0;
119 if(value >= 1.f * 0x7f / 0x80)
120 return 0xFF;
121 return lrintf((value + 1.f) * 0x80);
124 static inline SHORT f_to_16(float value)
126 if(value <= -1.f)
127 return 0x8000;
128 if(value >= 1.f * 0x7FFF / 0x8000)
129 return 0x7FFF;
130 return le16(lrintf(value * 0x8000));
133 static LONG f_to_24(float value)
135 if(value <= -1.f)
136 return 0x80000000;
137 if(value >= 1.f * 0x7FFFFF / 0x800000)
138 return 0x7FFFFF00;
139 return lrintf(value * 0x80000000U);
142 static inline LONG f_to_32(float value)
144 if(value <= -1.f)
145 return 0x80000000;
146 if(value >= 1.f * 0x7FFFFFFF / 0x80000000U) /* this rounds to 1.f */
147 return 0x7FFFFFFF;
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);
155 *fbuf = value;
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);
162 *fbuf += value;
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 */
217 switch(channel){
219 case 4: /* surround left */
220 value *= 0.24f;
221 dsb->put_aux(dsb, pos, 0, value);
222 break;
224 case 0: /* front left */
225 value *= 1.0f;
226 dsb->put_aux(dsb, pos, 0, value);
227 break;
229 case 5: /* surround right */
230 value *= 0.24f;
231 dsb->put_aux(dsb, pos, 1, value);
232 break;
234 case 1: /* front right */
235 value *= 1.0f;
236 dsb->put_aux(dsb, pos, 1, value);
237 break;
239 case 2: /* centre */
240 value *= 0.7;
241 dsb->put_aux(dsb, pos, 0, value);
242 dsb->put_aux(dsb, pos, 1, value);
243 break;
245 case 3:
246 /* LFE is totally ignored in dsound when downmixing to 2 channels */
247 break;
251 void put_surround712stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
253 /* based on analyzing a recording of a dsound downmix */
254 switch(channel){
256 case 6: /* back left */
257 value *= 0.24f;
258 dsb->put_aux(dsb, pos, 0, value);
259 break;
261 case 4: /* surround left */
262 value *= 0.24f;
263 dsb->put_aux(dsb, pos, 0, value);
264 break;
266 case 0: /* front left */
267 value *= 1.0f;
268 dsb->put_aux(dsb, pos, 0, value);
269 break;
271 case 7: /* back right */
272 value *= 0.24f;
273 dsb->put_aux(dsb, pos, 1, value);
274 break;
276 case 5: /* surround right */
277 value *= 0.24f;
278 dsb->put_aux(dsb, pos, 1, value);
279 break;
281 case 1: /* front right */
282 value *= 1.0f;
283 dsb->put_aux(dsb, pos, 1, value);
284 break;
286 case 2: /* centre */
287 value *= 0.7;
288 dsb->put_aux(dsb, pos, 0, value);
289 dsb->put_aux(dsb, pos, 1, value);
290 break;
292 case 3:
293 /* LFE is totally ignored in dsound when downmixing to 2 channels */
294 break;
298 void put_quad2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
300 /* based on pulseaudio's downmix algorithm */
301 switch(channel){
303 case 2: /* back left */
304 value *= 0.1f; /* (1/9) / (sum of left volumes) */
305 dsb->put_aux(dsb, pos, 0, value);
306 break;
308 case 0: /* front left */
309 value *= 0.9f; /* 1 / (sum of left volumes) */
310 dsb->put_aux(dsb, pos, 0, value);
311 break;
313 case 3: /* back right */
314 value *= 0.1f; /* (1/9) / (sum of right volumes) */
315 dsb->put_aux(dsb, pos, 1, value);
316 break;
318 case 1: /* front right */
319 value *= 0.9f; /* 1 / (sum of right volumes) */
320 dsb->put_aux(dsb, pos, 1, value);
321 break;
325 void mixieee32(float *src, float *dst, unsigned samples)
327 TRACE("%p - %p %d\n", src, dst, samples);
328 while (samples--)
329 *(dst++) += *(src++);
332 static void norm8(float *src, unsigned char *dst, unsigned samples)
334 TRACE("%p - %p %d\n", src, dst, samples);
335 while (samples--)
337 *dst = f_to_8(*src);
338 ++dst;
339 ++src;
343 static void norm16(float *src, SHORT *dst, unsigned samples)
345 TRACE("%p - %p %d\n", src, dst, samples);
346 while (samples--)
348 *dst = f_to_16(*src);
349 ++dst;
350 ++src;
354 static void norm24(float *src, BYTE *dst, unsigned samples)
356 TRACE("%p - %p %d\n", src, dst, samples);
357 while (samples--)
359 LONG t = f_to_24(*src);
360 dst[0] = (t >> 8) & 0xFF;
361 dst[1] = (t >> 16) & 0xFF;
362 dst[2] = t >> 24;
363 dst += 3;
364 ++src;
368 static void norm32(float *src, INT *dst, unsigned samples)
370 TRACE("%p - %p %d\n", src, dst, samples);
371 while (samples--)
373 *dst = f_to_32(*src);
374 ++dst;
375 ++src;
379 const normfunc normfunctions[4] = {
380 (normfunc)norm8,
381 (normfunc)norm16,
382 (normfunc)norm24,
383 (normfunc)norm32,