VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp@ 89383

Last change on this file since 89383 was 89382, checked in by vboxsync, 4 years ago

AudioMixBuffer: Added generic decoders and encoders for arbitrary channel counts using generic source->destionation channel mapping (the mapping may need more work). Instantiated the resampler code for up to 12 channels. Untested. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.2 KB
Line 
1/* $Id: AudioMixBuffer.cpp 89382 2021-05-31 00:03:03Z vboxsync $ */
2/** @file
3 * Audio mixing buffer for converting reading/writing audio data.
4 */
5
6/*
7 * Copyright (C) 2014-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @page pg_audio_mix_buffer Audio Mixer Buffer
19 *
20 * @section sec_audio_mix_buffer_volume Soft Volume Control
21 *
22 * The external code supplies an 8-bit volume (attenuation) value in the
23 * 0 .. 255 range. This represents 0 to -96dB attenuation where an input
24 * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
25 *
26 * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
27 * represents doubling the sample value.
28 *
29 * For internal use, the volume control needs to be converted to a 16-bit
30 * (sort of) exponential value between 1 and 65536. This is used with fixed
31 * point arithmetic such that 65536 means 1.0 and 1 means 1/65536.
32 *
33 * For actual volume calculation, 33.31 fixed point is used. Maximum (or
34 * unattenuated) volume is represented as 0x40000000; conveniently, this
35 * value fits into a uint32_t.
36 *
37 * To enable fast processing, the maximum volume must be a power of two
38 * and must not have a sign when converted to int32_t. While 0x80000000
39 * violates these constraints, 0x40000000 does not.
40 */
41
42
43/*********************************************************************************************************************************
44* Header Files *
45*********************************************************************************************************************************/
46#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
47#if defined(VBOX_AUDIO_MIX_BUFFER_TESTCASE) && !defined(RT_STRICT)
48# define RT_STRICT /* Run the testcase with assertions because the main functions doesn't return on invalid input. */
49#endif
50#include <VBox/log.h>
51
52#if 0
53/*
54 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
55 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
56 * to your needs before using this!
57 */
58# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
59# ifdef RT_OS_WINDOWS
60# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
61# else
62# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
63# endif
64/* Warning: Enabling this will generate *huge* logs! */
65//# define AUDIOMIXBUF_DEBUG_MACROS
66#endif
67
68#include <iprt/asm-math.h>
69#include <iprt/assert.h>
70#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
71# include <iprt/file.h>
72#endif
73#include <iprt/mem.h>
74#include <iprt/string.h> /* For RT_BZERO. */
75
76#ifdef VBOX_AUDIO_TESTCASE
77# define LOG_ENABLED
78# include <iprt/stream.h>
79#endif
80#include <iprt/errcore.h>
81#include <VBox/vmm/pdmaudioinline.h>
82
83#include "AudioMixBuffer.h"
84
85
86/*********************************************************************************************************************************
87* Defined Constants And Macros *
88*********************************************************************************************************************************/
89#ifndef VBOX_AUDIO_TESTCASE
90# ifdef DEBUG
91# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
92# define AUDMIXBUF_LOG_ENABLED
93# else
94# define AUDMIXBUF_LOG(x) do {} while (0)
95# endif
96#else /* VBOX_AUDIO_TESTCASE */
97# define AUDMIXBUF_LOG(x) RTPrintf x
98# define AUDMIXBUF_LOG_ENABLED
99#endif
100
101
102/** Bit shift for fixed point conversion.
103 * @sa @ref sec_audio_mix_buffer_volume */
104#define AUDIOMIXBUF_VOL_SHIFT 30
105
106/** Internal representation of 0dB volume (1.0 in fixed point).
107 * @sa @ref sec_audio_mix_buffer_volume */
108#define AUDIOMIXBUF_VOL_0DB (1 << AUDIOMIXBUF_VOL_SHIFT)
109AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */
110AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000); /* For now -- when only attenuation is used. */
111
112
113/*********************************************************************************************************************************
114* Global Variables *
115*********************************************************************************************************************************/
116/** Logarithmic/exponential volume conversion table.
117 * @sa @ref sec_audio_mix_buffer_volume
118 */
119static uint32_t const s_aVolumeConv[256] =
120{
121 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
122 1, 2, 2, 2, 2, 2, 2, 2, /* 15 */
123 2, 2, 2, 2, 2, 3, 3, 3, /* 23 */
124 3, 3, 3, 3, 4, 4, 4, 4, /* 31 */
125 4, 4, 5, 5, 5, 5, 5, 6, /* 39 */
126 6, 6, 6, 7, 7, 7, 8, 8, /* 47 */
127 8, 9, 9, 10, 10, 10, 11, 11, /* 55 */
128 12, 12, 13, 13, 14, 15, 15, 16, /* 63 */
129 17, 17, 18, 19, 20, 21, 22, 23, /* 71 */
130 24, 25, 26, 27, 28, 29, 31, 32, /* 79 */
131 33, 35, 36, 38, 40, 41, 43, 45, /* 87 */
132 47, 49, 52, 54, 56, 59, 61, 64, /* 95 */
133 67, 70, 73, 76, 79, 83, 87, 91, /* 103 */
134 95, 99, 103, 108, 112, 117, 123, 128, /* 111 */
135 134, 140, 146, 152, 159, 166, 173, 181, /* 119 */
136 189, 197, 206, 215, 225, 235, 245, 256, /* 127 */
137 267, 279, 292, 304, 318, 332, 347, 362, /* 135 */
138 378, 395, 412, 431, 450, 470, 490, 512, /* 143 */
139 535, 558, 583, 609, 636, 664, 693, 724, /* 151 */
140 756, 790, 825, 861, 899, 939, 981, 1024, /* 159 */
141 1069, 1117, 1166, 1218, 1272, 1328, 1387, 1448, /* 167 */
142 1512, 1579, 1649, 1722, 1798, 1878, 1961, 2048, /* 175 */
143 2139, 2233, 2332, 2435, 2543, 2656, 2774, 2896, /* 183 */
144 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, /* 191 */
145 4277, 4467, 4664, 4871, 5087, 5312, 5547, 5793, /* 199 */
146 6049, 6317, 6597, 6889, 7194, 7512, 7845, 8192, /* 207 */
147 8555, 8933, 9329, 9742, 10173, 10624, 11094, 11585, /* 215 */
148 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, /* 223 */
149 17109, 17867, 18658, 19484, 20347, 21247, 22188, 23170, /* 231 */
150 24196, 25268, 26386, 27554, 28774, 30048, 31379, 32768, /* 239 */
151 34219, 35734, 37316, 38968, 40693, 42495, 44376, 46341, /* 247 */
152 48393, 50535, 52773, 55109, 57549, 60097, 62757, 65536, /* 255 */
153};
154
155
156
157#ifdef VBOX_STRICT
158# ifdef UNUSED
159
160/**
161 * Prints a single mixing buffer.
162 * Internal helper function for debugging. Do not use directly.
163 *
164 * @returns VBox status code.
165 * @param pMixBuf Mixing buffer to print.
166 * @param pszFunc Function name to log this for.
167 * @param uIdtLvl Indention level to use.
168 */
169static void audioMixBufDbgPrintSingle(PAUDIOMIXBUF pMixBuf, const char *pszFunc, uint16_t uIdtLvl)
170{
171 Log(("%s: %*s %s: offRead=%RU32, offWrite=%RU32 -> %RU32/%RU32\n",
172 pszFunc, uIdtLvl * 4, "",
173 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cUsed, pMixBuf->cFrames));
174}
175
176static void audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc)
177{
178 audioMixBufDbgPrintSingle(pMixBuf, pszFunc, 0 /* iIdtLevel */);
179}
180
181/**
182 * Validates a single mixing buffer.
183 *
184 * @return @true if the buffer state is valid or @false if not.
185 * @param pMixBuf Mixing buffer to validate.
186 */
187static bool audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf)
188{
189 //const uint32_t offReadEnd = (pMixBuf->offRead + pMixBuf->cUsed) % pMixBuf->cFrames;
190 //const uint32_t offWriteEnd = (pMixBuf->offWrite + (pMixBuf->cFrames - pMixBuf->cUsed)) % pMixBuf->cFrames;
191
192 bool fValid = true;
193
194 AssertStmt(pMixBuf->offRead <= pMixBuf->cFrames, fValid = false);
195 AssertStmt(pMixBuf->offWrite <= pMixBuf->cFrames, fValid = false);
196 AssertStmt(pMixBuf->cUsed <= pMixBuf->cFrames, fValid = false);
197
198 if (pMixBuf->offWrite > pMixBuf->offRead)
199 {
200 if (pMixBuf->offWrite - pMixBuf->offRead != pMixBuf->cUsed)
201 fValid = false;
202 }
203 else if (pMixBuf->offWrite < pMixBuf->offRead)
204 {
205 if (pMixBuf->offWrite + pMixBuf->cFrames - pMixBuf->offRead != pMixBuf->cUsed)
206 fValid = false;
207 }
208
209 if (!fValid)
210 {
211 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
212 AssertFailed();
213 }
214
215 return fValid;
216}
217
218# endif /* UNUSED */
219#endif /* VBOX_STRICT */
220
221
222/**
223 * Merges @a i32Src into the value stored at @a pi32Dst.
224 *
225 * @param pi32Dst The value to merge @a i32Src into.
226 * @param i32Src The new value to add.
227 */
228DECL_FORCE_INLINE(void) audioMixBufBlendSample(int32_t *pi32Dst, int32_t i32Src)
229{
230 if (i32Src)
231 {
232 int64_t const i32Dst = *pi32Dst;
233 if (!i32Dst)
234 *pi32Dst = i32Src;
235 else
236 *pi32Dst = (int32_t)(((int64_t)i32Dst + i32Src) / 2);
237 }
238}
239
240
241/**
242 * Variant of audioMixBufBlendSample that returns the result rather than storing it.
243 *
244 * This is used for stereo -> mono.
245 */
246DECL_FORCE_INLINE(int32_t) audioMixBufBlendSampleRet(int32_t i32Sample1, int32_t i32Sample2)
247{
248 if (!i32Sample1)
249 return i32Sample2;
250 if (!i32Sample2)
251 return i32Sample1;
252 return (int32_t)(((int64_t)i32Sample1 + i32Sample2) / 2);
253}
254
255
256/**
257 * Blends (merges) the source buffer into the destination buffer.
258 *
259 * We're taking a very simple approach here, working sample by sample:
260 * - if one is silent, use the other one.
261 * - otherwise sum and divide by two.
262 *
263 * @param pi32Dst The destination stream buffer (input and output).
264 * @param pi32Src The source stream buffer.
265 * @param cFrames Number of frames to process.
266 * @param cChannels Number of channels.
267 */
268static void audioMixBufBlendBuffer(int32_t *pi32Dst, int32_t const *pi32Src, uint32_t cFrames, uint8_t cChannels)
269{
270 switch (cChannels)
271 {
272 case 2:
273 while (cFrames-- > 0)
274 {
275 audioMixBufBlendSample(&pi32Dst[0], pi32Src[0]);
276 audioMixBufBlendSample(&pi32Dst[1], pi32Src[1]);
277 pi32Dst += 2;
278 pi32Src += 2;
279 }
280 break;
281
282 default:
283 cFrames *= cChannels;
284 RT_FALL_THROUGH();
285 case 1:
286 while (cFrames-- > 0)
287 {
288 audioMixBufBlendSample(pi32Dst, pi32Src[0]);
289 pi32Dst++;
290 pi32Src++;
291 }
292 break;
293 }
294}
295
296
297#ifdef AUDIOMIXBUF_DEBUG_MACROS
298# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
299#elif defined(VBOX_AUDIO_TESTCASE_VERBOSE) /* Warning: VBOX_AUDIO_TESTCASE_VERBOSE will generate huge logs! */
300# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
301#else
302# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
303#endif
304
305/**
306 * Macro for generating the conversion routines from/to different formats.
307 * Be careful what to pass in/out, as most of the macros are optimized for speed and
308 * thus don't do any bounds checking!
309 *
310 * @note Currently does not handle any endianness conversion yet!
311 */
312#define AUDMIXBUF_CONVERT(a_Name, a_Type, _aMin, _aMax, _aSigned, _aShift) \
313 /* Clips a specific output value to a single sample value. */ \
314 DECLINLINE(int32_t) audioMixBufSampleFrom##a_Name(a_Type aVal) \
315 { \
316 /* left shifting of signed values is not defined, therefore the intermediate uint64_t cast */ \
317 if (_aSigned) \
318 return (int32_t) (((uint32_t) ((int32_t) aVal )) << (32 - _aShift)); \
319 return (int32_t) (((uint32_t) ((int32_t) aVal - ((_aMax >> 1) + 1))) << (32 - _aShift)); \
320 } \
321 \
322 /* Clips a single sample value to a specific output value. */ \
323 DECLINLINE(a_Type) audioMixBufSampleTo##a_Name(int32_t iVal) \
324 { \
325 if (_aSigned) \
326 return (a_Type) (iVal >> (32 - _aShift)); \
327 return (a_Type) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1)); \
328 } \
329 \
330 /* Encoders for peek: */ \
331 \
332 /* Generic */ \
333 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncodeGeneric,a_Name)(void *pvDst, int32_t const *pi32Src, uint32_t cFrames, \
334 PAUDIOMIXBUFPEEKSTATE pState) \
335 { \
336 RT_NOREF_PV(pState); \
337 uintptr_t const cSrcChannels = pState->cSrcChannels; \
338 uintptr_t const cDstChannels = pState->cDstChannels; \
339 a_Type *pDst = (a_Type *)pvDst; \
340 while (cFrames-- > 0) \
341 { \
342 uintptr_t idxDst = cDstChannels; \
343 while (idxDst-- > 0) \
344 { \
345 int8_t idxSrc = pState->aidxChannelMap[idxDst]; \
346 if (idxSrc >= 0) \
347 pDst[idxDst] = audioMixBufSampleTo##a_Name(pi32Src[idxSrc]); \
348 else if (idxSrc != -2) \
349 pDst[idxDst] = (_aSigned) ? 0 : (_aMax >> 1); \
350 else \
351 pDst[idxDst] = 0; \
352 } \
353 pDst += cDstChannels; \
354 pi32Src += cSrcChannels; \
355 } \
356 } \
357 \
358 /* 2ch -> 2ch */ \
359 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode2ChTo2Ch,a_Name)(void *pvDst, int32_t const *pi32Src, uint32_t cFrames, \
360 PAUDIOMIXBUFPEEKSTATE pState) \
361 { \
362 RT_NOREF_PV(pState); \
363 a_Type *pDst = (a_Type *)pvDst; \
364 while (cFrames-- > 0) \
365 { \
366 pDst[0] = audioMixBufSampleTo##a_Name(pi32Src[0]); \
367 pDst[1] = audioMixBufSampleTo##a_Name(pi32Src[1]); \
368 AUDMIXBUF_MACRO_LOG(("%p: %RI32 / %RI32 => %RI32 / %RI32\n", \
369 &pi32Src[0], pi32Src[0], pi32Src[1], (int32_t)pDst[0], (int32_t)pDst[1])); \
370 pDst += 2; \
371 pi32Src += 2; \
372 } \
373 } \
374 \
375 /* 2ch -> 1ch */ \
376 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode2ChTo1Ch,a_Name)(void *pvDst, int32_t const *pi32Src, uint32_t cFrames, \
377 PAUDIOMIXBUFPEEKSTATE pState) \
378 { \
379 RT_NOREF_PV(pState); \
380 a_Type *pDst = (a_Type *)pvDst; \
381 while (cFrames-- > 0) \
382 { \
383 pDst[0] = audioMixBufSampleTo##a_Name(audioMixBufBlendSampleRet(pi32Src[0], pi32Src[1])); \
384 pDst += 1; \
385 pi32Src += 2; \
386 } \
387 } \
388 \
389 /* 1ch -> 2ch */ \
390 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode1ChTo2Ch,a_Name)(void *pvDst, int32_t const *pi32Src, uint32_t cFrames, \
391 PAUDIOMIXBUFPEEKSTATE pState) \
392 { \
393 RT_NOREF_PV(pState); \
394 a_Type *pDst = (a_Type *)pvDst; \
395 while (cFrames-- > 0) \
396 { \
397 pDst[0] = pDst[1] = audioMixBufSampleTo##a_Name(pi32Src[0]); \
398 pDst += 2; \
399 pi32Src += 1; \
400 } \
401 } \
402 /* 1ch -> 1ch */ \
403 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode1ChTo1Ch,a_Name)(void *pvDst, int32_t const *pi32Src, uint32_t cFrames, \
404 PAUDIOMIXBUFPEEKSTATE pState) \
405 { \
406 RT_NOREF_PV(pState); \
407 a_Type *pDst = (a_Type *)pvDst; \
408 while (cFrames-- > 0) \
409 { \
410 pDst[0] = audioMixBufSampleTo##a_Name(pi32Src[0]); \
411 pDst += 1; \
412 pi32Src += 1; \
413 } \
414 } \
415 \
416 /* Decoders for write: */ \
417 \
418 /* Generic */ \
419 static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecodeGeneric,a_Name)(int32_t *pi32Dst, void const *pvSrc, uint32_t cFrames, \
420 PAUDIOMIXBUFWRITESTATE pState) \
421 { \
422 RT_NOREF_PV(pState); \
423 uintptr_t const cSrcChannels = pState->cSrcChannels; \
424 uintptr_t const cDstChannels = pState->cDstChannels; \
425 a_Type const *pSrc = (a_Type const *)pvSrc; \
426 while (cFrames-- > 0) \
427 { \
428 uintptr_t idxDst = cDstChannels; \
429 while (idxDst-- > 0) \
430 { \
431 int8_t idxSrc = pState->aidxChannelMap[idxDst]; \
432 if (idxSrc >= 0) \
433 pi32Dst[idxDst] = audioMixBufSampleTo##a_Name(pSrc[idxSrc]); \
434 else if (idxSrc != -2) \
435 pi32Dst[idxDst] = (_aSigned) ? 0 : (_aMax >> 1); \
436 else \
437 pi32Dst[idxDst] = 0; \
438 } \
439 pi32Dst += cDstChannels; \
440 pSrc += cSrcChannels; \
441 } \
442 } \
443 \
444 /* 2ch -> 2ch */ \
445 static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode2ChTo2Ch,a_Name)(int32_t *pi32Dst, void const *pvSrc, uint32_t cFrames, \
446 PAUDIOMIXBUFWRITESTATE pState) \
447 { \
448 RT_NOREF_PV(pState); \
449 a_Type const *pSrc = (a_Type const *)pvSrc; \
450 while (cFrames-- > 0) \
451 { \
452 pi32Dst[0] = audioMixBufSampleFrom##a_Name(pSrc[0]); \
453 pi32Dst[1] = audioMixBufSampleFrom##a_Name(pSrc[1]); \
454 AUDMIXBUF_MACRO_LOG(("%p: %RI32 / %RI32 => %RI32 / %RI32\n", \
455 &pSrc[0], (int32_t)pSrc[0], (int32_t)pSrc[1], pi32Dst[0], pi32Dst[1])); \
456 pi32Dst += 2; \
457 pSrc += 2; \
458 } \
459 } \
460 \
461 /* 2ch -> 1ch */ \
462 static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode2ChTo1Ch,a_Name)(int32_t *pi32Dst, void const *pvSrc, uint32_t cFrames, \
463 PAUDIOMIXBUFWRITESTATE pState) \
464 { \
465 RT_NOREF_PV(pState); \
466 a_Type const *pSrc = (a_Type const *)pvSrc; \
467 while (cFrames-- > 0) \
468 { \
469 pi32Dst[0] = audioMixBufBlendSampleRet(audioMixBufSampleFrom##a_Name(pSrc[0]), audioMixBufSampleFrom##a_Name(pSrc[1])); \
470 pi32Dst += 1; \
471 pSrc += 2; \
472 } \
473 } \
474 \
475 /* 1ch -> 2ch */ \
476 static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode1ChTo2Ch,a_Name)(int32_t *pi32Dst, void const *pvSrc, uint32_t cFrames, \
477 PAUDIOMIXBUFWRITESTATE pState) \
478 { \
479 RT_NOREF_PV(pState); \
480 a_Type const *pSrc = (a_Type const *)pvSrc; \
481 while (cFrames-- > 0) \
482 { \
483 pi32Dst[1] = pi32Dst[0] = audioMixBufSampleFrom##a_Name(pSrc[0]); \
484 pi32Dst += 2; \
485 pSrc += 1; \
486 } \
487 } \
488 \
489 /* 1ch -> 1ch */ \
490 static DECLCALLBACK(void) RT_CONCAT(audioMixBufDecode1ChTo1Ch,a_Name)(int32_t *pi32Dst, void const *pvSrc, uint32_t cFrames, \
491 PAUDIOMIXBUFWRITESTATE pState) \
492 { \
493 RT_NOREF_PV(pState); \
494 a_Type const *pSrc = (a_Type const *)pvSrc; \
495 while (cFrames-- > 0) \
496 { \
497 pi32Dst[0] = audioMixBufSampleFrom##a_Name(pSrc[0]); \
498 pi32Dst += 1; \
499 pSrc += 1; \
500 } \
501 } \
502 \
503 /* Decoders for blending: */ \
504 \
505 /* Generic */ \
506 static DECLCALLBACK(void) RT_CONCAT3(audioMixBufDecodeGeneric,a_Name,Blend)(int32_t *pi32Dst, void const *pvSrc, \
507 uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState) \
508 { \
509 RT_NOREF_PV(pState); \
510 uintptr_t const cSrcChannels = pState->cSrcChannels; \
511 uintptr_t const cDstChannels = pState->cDstChannels; \
512 a_Type const *pSrc = (a_Type const *)pvSrc; \
513 while (cFrames-- > 0) \
514 { \
515 uintptr_t idxDst = cDstChannels; \
516 while (idxDst-- > 0) \
517 { \
518 int8_t idxSrc = pState->aidxChannelMap[idxDst]; \
519 if (idxSrc >= 0) \
520 audioMixBufBlendSample(&pi32Dst[idxDst], audioMixBufSampleTo##a_Name(pSrc[idxSrc])); \
521 } \
522 pi32Dst += cDstChannels; \
523 pSrc += cSrcChannels; \
524 } \
525 } \
526 \
527 /* 2ch -> 2ch */ \
528 static DECLCALLBACK(void) RT_CONCAT3(audioMixBufDecode2ChTo2Ch,a_Name,Blend)(int32_t *pi32Dst, void const *pvSrc, \
529 uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState) \
530 { \
531 RT_NOREF_PV(pState); \
532 a_Type const *pSrc = (a_Type const *)pvSrc; \
533 while (cFrames-- > 0) \
534 { \
535 audioMixBufBlendSample(&pi32Dst[0], audioMixBufSampleFrom##a_Name(pSrc[0])); \
536 audioMixBufBlendSample(&pi32Dst[1], audioMixBufSampleFrom##a_Name(pSrc[1])); \
537 AUDMIXBUF_MACRO_LOG(("%p: %RI32 / %RI32 => %RI32 / %RI32\n", \
538 &pSrc[0], (int32_t)pSrc[0], (int32_t)pSrc[1], pi32Dst[0], pi32Dst[1])); \
539 pi32Dst += 2; \
540 pSrc += 2; \
541 } \
542 } \
543 \
544 /* 2ch -> 1ch */ \
545 static DECLCALLBACK(void) RT_CONCAT3(audioMixBufDecode2ChTo1Ch,a_Name,Blend)(int32_t *pi32Dst, void const *pvSrc, \
546 uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState) \
547 { \
548 RT_NOREF_PV(pState); \
549 a_Type const *pSrc = (a_Type const *)pvSrc; \
550 while (cFrames-- > 0) \
551 { \
552 audioMixBufBlendSample(&pi32Dst[0], audioMixBufBlendSampleRet(audioMixBufSampleFrom##a_Name(pSrc[0]), \
553 audioMixBufSampleFrom##a_Name(pSrc[1]))); \
554 pi32Dst += 1; \
555 pSrc += 2; \
556 } \
557 } \
558 \
559 /* 1ch -> 2ch */ \
560 static DECLCALLBACK(void) RT_CONCAT3(audioMixBufDecode1ChTo2Ch,a_Name,Blend)(int32_t *pi32Dst, void const *pvSrc, \
561 uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState) \
562 { \
563 RT_NOREF_PV(pState); \
564 a_Type const *pSrc = (a_Type const *)pvSrc; \
565 while (cFrames-- > 0) \
566 { \
567 int32_t const i32Src = audioMixBufSampleFrom##a_Name(pSrc[0]); \
568 audioMixBufBlendSample(&pi32Dst[0], i32Src); \
569 audioMixBufBlendSample(&pi32Dst[1], i32Src); \
570 pi32Dst += 2; \
571 pSrc += 1; \
572 } \
573 } \
574 \
575 /* 1ch -> 1ch */ \
576 static DECLCALLBACK(void) RT_CONCAT3(audioMixBufDecode1ChTo1Ch,a_Name,Blend)(int32_t *pi32Dst, void const *pvSrc, \
577 uint32_t cFrames, PAUDIOMIXBUFWRITESTATE pState) \
578 { \
579 RT_NOREF_PV(pState); \
580 a_Type const *pSrc = (a_Type const *)pvSrc; \
581 while (cFrames-- > 0) \
582 { \
583 audioMixBufBlendSample(&pi32Dst[0], audioMixBufSampleFrom##a_Name(pSrc[0])); \
584 pi32Dst += 1; \
585 pSrc += 1; \
586 } \
587 }
588
589
590/* audioMixBufConvXXXS8: 8-bit, signed. */
591AUDMIXBUF_CONVERT(S8 /* Name */, int8_t, INT8_MIN /* Min */, INT8_MAX /* Max */, true /* fSigned */, 8 /* cShift */)
592/* audioMixBufConvXXXU8: 8-bit, unsigned. */
593AUDMIXBUF_CONVERT(U8 /* Name */, uint8_t, 0 /* Min */, UINT8_MAX /* Max */, false /* fSigned */, 8 /* cShift */)
594/* audioMixBufConvXXXS16: 16-bit, signed. */
595AUDMIXBUF_CONVERT(S16 /* Name */, int16_t, INT16_MIN /* Min */, INT16_MAX /* Max */, true /* fSigned */, 16 /* cShift */)
596/* audioMixBufConvXXXU16: 16-bit, unsigned. */
597AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0 /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)
598/* audioMixBufConvXXXS32: 32-bit, signed. */
599AUDMIXBUF_CONVERT(S32 /* Name */, int32_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)
600/* audioMixBufConvXXXU32: 32-bit, unsigned. */
601AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)
602/* audioMixBufConvXXXRaw: 32-bit stored as 64-bit, signed. */
603AUDMIXBUF_CONVERT(Raw /* Name */, int64_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)
604
605#undef AUDMIXBUF_CONVERT
606#undef AUDMIXBUF_MACRO_LOG
607
608
609/*
610 * Resampling core.
611 */
612/** @todo Separate down- and up-sampling, borrow filter code from RDP. */
613#define COPY_LAST_FRAME_1CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
614 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
615 } while (0)
616#define COPY_LAST_FRAME_2CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
617 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
618 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
619 } while (0)
620#define COPY_LAST_FRAME_3CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
621 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
622 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
623 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
624 } while (0)
625#define COPY_LAST_FRAME_4CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
626 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
627 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
628 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
629 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
630 } while (0)
631#define COPY_LAST_FRAME_5CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
632 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
633 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
634 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
635 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
636 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
637 } while (0)
638#define COPY_LAST_FRAME_6CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
639 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
640 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
641 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
642 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
643 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
644 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
645 } while (0)
646#define COPY_LAST_FRAME_7CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
647 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
648 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
649 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
650 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
651 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
652 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
653 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
654 } while (0)
655#define COPY_LAST_FRAME_8CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
656 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
657 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
658 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
659 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
660 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
661 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
662 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
663 (a_pi32Dst)[7] = (a_pi32Src)[7]; \
664 } while (0)
665#define COPY_LAST_FRAME_9CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
666 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
667 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
668 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
669 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
670 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
671 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
672 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
673 (a_pi32Dst)[7] = (a_pi32Src)[7]; \
674 (a_pi32Dst)[8] = (a_pi32Src)[8]; \
675 } while (0)
676#define COPY_LAST_FRAME_10CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
677 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
678 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
679 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
680 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
681 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
682 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
683 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
684 (a_pi32Dst)[7] = (a_pi32Src)[7]; \
685 (a_pi32Dst)[8] = (a_pi32Src)[8]; \
686 (a_pi32Dst)[9] = (a_pi32Src)[9]; \
687 } while (0)
688#define COPY_LAST_FRAME_11CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
689 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
690 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
691 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
692 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
693 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
694 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
695 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
696 (a_pi32Dst)[7] = (a_pi32Src)[7]; \
697 (a_pi32Dst)[8] = (a_pi32Src)[8]; \
698 (a_pi32Dst)[9] = (a_pi32Src)[9]; \
699 (a_pi32Dst)[10] = (a_pi32Src)[10]; \
700 } while (0)
701#define COPY_LAST_FRAME_12CH(a_pi32Dst, a_pi32Src, a_cChannels) do { \
702 (a_pi32Dst)[0] = (a_pi32Src)[0]; \
703 (a_pi32Dst)[1] = (a_pi32Src)[1]; \
704 (a_pi32Dst)[2] = (a_pi32Src)[2]; \
705 (a_pi32Dst)[3] = (a_pi32Src)[3]; \
706 (a_pi32Dst)[4] = (a_pi32Src)[4]; \
707 (a_pi32Dst)[5] = (a_pi32Src)[5]; \
708 (a_pi32Dst)[6] = (a_pi32Src)[6]; \
709 (a_pi32Dst)[7] = (a_pi32Src)[7]; \
710 (a_pi32Dst)[8] = (a_pi32Src)[8]; \
711 (a_pi32Dst)[9] = (a_pi32Src)[9]; \
712 (a_pi32Dst)[10] = (a_pi32Src)[10]; \
713 (a_pi32Dst)[11] = (a_pi32Src)[11]; \
714 } while (0)
715
716#define INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_iCh) \
717 (a_pi32Dst)[a_iCh] = ((a_pi32Last)[a_iCh] * a_i64FactorLast + (a_pi32Src)[a_iCh] * a_i64FactorCur) >> 32
718#define INTERPOLATE_1CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
719 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
720 } while (0)
721#define INTERPOLATE_2CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
722 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
723 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
724 } while (0)
725#define INTERPOLATE_3CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
726 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
727 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
728 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
729 } while (0)
730#define INTERPOLATE_4CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
731 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
732 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
733 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
734 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
735 } while (0)
736#define INTERPOLATE_5CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
737 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
738 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
739 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
740 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
741 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
742 } while (0)
743#define INTERPOLATE_6CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
744 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
745 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
746 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
747 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
748 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
749 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
750 } while (0)
751#define INTERPOLATE_7CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
752 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
753 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
754 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
755 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
756 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
757 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
758 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
759 } while (0)
760#define INTERPOLATE_8CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
761 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
762 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
763 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
764 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
765 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
766 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
767 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
768 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 7); \
769 } while (0)
770#define INTERPOLATE_9CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
771 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
772 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
773 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
774 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
775 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
776 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
777 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
778 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 7); \
779 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 8); \
780 } while (0)
781#define INTERPOLATE_10CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
782 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
783 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
784 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
785 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
786 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
787 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
788 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
789 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 7); \
790 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 8); \
791 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 9); \
792 } while (0)
793#define INTERPOLATE_11CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
794 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
795 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
796 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
797 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
798 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
799 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
800 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
801 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 7); \
802 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 8); \
803 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 9); \
804 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 10); \
805 } while (0)
806#define INTERPOLATE_12CH(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
807 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 0); \
808 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 1); \
809 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 2); \
810 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 3); \
811 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 4); \
812 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 5); \
813 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 6); \
814 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 7); \
815 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 8); \
816 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 9); \
817 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 10); \
818 INTERPOLATE_ONE(a_pi32Dst, a_pi32Src, a_pi32Last, a_i64FactorCur, a_i64FactorLast, 11); \
819 } while (0)
820
821#define AUDIOMIXBUF_RESAMPLE(a_cChannels, a_Suffix) \
822 /** @returns Number of destination frames written. */ \
823 static DECLCALLBACK(uint32_t) \
824 audioMixBufResample##a_cChannels##Ch##a_Suffix(int32_t *pi32Dst, uint32_t cDstFrames, \
825 int32_t const *pi32Src, uint32_t cSrcFrames, uint32_t *pcSrcFramesRead, \
826 PAUDIOSTREAMRATE pRate) \
827 { \
828 Log5(("Src: %RU32 L %RU32; Dst: %RU32 L%RU32; uDstInc=%#RX64\n", \
829 pRate->offSrc, cSrcFrames, RT_HI_U32(pRate->offDst), cDstFrames, pRate->uDstInc)); \
830 int32_t * const pi32DstStart = pi32Dst; \
831 int32_t const * const pi32SrcStart = pi32Src; \
832 \
833 int32_t ai32LastFrame[a_cChannels]; \
834 COPY_LAST_FRAME_##a_cChannels##CH(ai32LastFrame, pRate->SrcLast.ai32Samples, a_cChannels); \
835 \
836 while (cDstFrames > 0 && cSrcFrames > 0) \
837 { \
838 int32_t const cSrcNeeded = RT_HI_U32(pRate->offDst) - pRate->offSrc + 1; \
839 if (cSrcNeeded > 0) \
840 { \
841 if ((uint32_t)cSrcNeeded + 1 < cSrcFrames) \
842 { \
843 pRate->offSrc += (uint32_t)cSrcNeeded; \
844 cSrcFrames -= (uint32_t)cSrcNeeded; \
845 pi32Src += (uint32_t)cSrcNeeded * a_cChannels; \
846 COPY_LAST_FRAME_##a_cChannels##CH(ai32LastFrame, &pi32Src[-a_cChannels], a_cChannels); \
847 } \
848 else \
849 { \
850 pi32Src += cSrcFrames * a_cChannels; \
851 pRate->offSrc += cSrcFrames; \
852 COPY_LAST_FRAME_##a_cChannels##CH(pRate->SrcLast.ai32Samples, &pi32Src[-a_cChannels], a_cChannels); \
853 *pcSrcFramesRead = (pi32Src - pi32SrcStart) / a_cChannels; \
854 return (pi32Dst - pi32DstStart) / a_cChannels; \
855 } \
856 } \
857 \
858 /* Interpolate. */ \
859 int64_t const offFactorCur = pRate->offDst & UINT32_MAX; \
860 int64_t const offFactorLast = (int64_t)_4G - offFactorCur; \
861 INTERPOLATE_##a_cChannels##CH(pi32Dst, pi32Src, ai32LastFrame, offFactorCur, offFactorLast, a_cChannels); \
862 \
863 /* Advance. */ \
864 pRate->offDst += pRate->uDstInc; \
865 pi32Dst += a_cChannels; \
866 cDstFrames -= 1; \
867 } \
868 \
869 COPY_LAST_FRAME_##a_cChannels##CH(pRate->SrcLast.ai32Samples, ai32LastFrame, a_cChannels); \
870 *pcSrcFramesRead = (pi32Src - pi32SrcStart) / a_cChannels; \
871 return (pi32Dst - pi32DstStart) / a_cChannels; \
872 }
873
874AUDIOMIXBUF_RESAMPLE(1,Generic)
875AUDIOMIXBUF_RESAMPLE(2,Generic)
876AUDIOMIXBUF_RESAMPLE(3,Generic)
877AUDIOMIXBUF_RESAMPLE(4,Generic)
878AUDIOMIXBUF_RESAMPLE(5,Generic)
879AUDIOMIXBUF_RESAMPLE(6,Generic)
880AUDIOMIXBUF_RESAMPLE(7,Generic)
881AUDIOMIXBUF_RESAMPLE(8,Generic)
882AUDIOMIXBUF_RESAMPLE(9,Generic)
883AUDIOMIXBUF_RESAMPLE(10,Generic)
884AUDIOMIXBUF_RESAMPLE(11,Generic)
885AUDIOMIXBUF_RESAMPLE(12,Generic)
886
887
888/**
889 * Resets the resampling state unconditionally.
890 *
891 * @param pRate The state to reset.
892 */
893static void audioMixBufRateResetAlways(PAUDIOSTREAMRATE pRate)
894{
895 pRate->offDst = 0;
896 pRate->offSrc = 0;
897 for (uintptr_t i = 0; i < RT_ELEMENTS(pRate->SrcLast.ai32Samples); i++)
898 pRate->SrcLast.ai32Samples[0] = 0;
899}
900
901
902/**
903 * Resets the resampling state.
904 *
905 * @param pRate The state to reset.
906 */
907DECLINLINE(void) audioMixBufRateReset(PAUDIOSTREAMRATE pRate)
908{
909 if (pRate->offDst == 0)
910 { /* likely */ }
911 else
912 {
913 Assert(!pRate->fNoConversionNeeded);
914 audioMixBufRateResetAlways(pRate);
915 }
916}
917
918
919/**
920 * Initializes the frame rate converter state.
921 *
922 * @returns VBox status code.
923 * @param pRate The state to initialize.
924 * @param uSrcHz The source frame rate.
925 * @param uDstHz The destination frame rate.
926 * @param cChannels The number of channels in a frame.
927 */
928DECLINLINE(int) audioMixBufRateInit(PAUDIOSTREAMRATE pRate, uint32_t uSrcHz, uint32_t uDstHz, uint8_t cChannels)
929{
930 /*
931 * Do we need to set up frequency conversion?
932 *
933 * Some examples to get an idea of what uDstInc holds:
934 * 44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296)
935 * 22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648)
936 * 44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592)
937 * 44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2)
938 * 48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109)
939 */
940 audioMixBufRateResetAlways(pRate);
941 if (uSrcHz == uDstHz)
942 {
943 pRate->fNoConversionNeeded = true;
944 pRate->uDstInc = RT_BIT_64(32);
945 pRate->pfnResample = NULL;
946 }
947 else
948 {
949 pRate->fNoConversionNeeded = false;
950 pRate->uDstInc = ((uint64_t)uSrcHz << 32) / uDstHz;
951 AssertReturn(uSrcHz != 0, VERR_INVALID_PARAMETER);
952 switch (cChannels)
953 {
954 case 1: pRate->pfnResample = audioMixBufResample1ChGeneric; break;
955 case 2: pRate->pfnResample = audioMixBufResample2ChGeneric; break;
956 case 3: pRate->pfnResample = audioMixBufResample3ChGeneric; break;
957 case 4: pRate->pfnResample = audioMixBufResample4ChGeneric; break;
958 case 5: pRate->pfnResample = audioMixBufResample5ChGeneric; break;
959 case 6: pRate->pfnResample = audioMixBufResample6ChGeneric; break;
960 case 7: pRate->pfnResample = audioMixBufResample7ChGeneric; break;
961 case 8: pRate->pfnResample = audioMixBufResample8ChGeneric; break;
962 case 9: pRate->pfnResample = audioMixBufResample9ChGeneric; break;
963 case 10: pRate->pfnResample = audioMixBufResample10ChGeneric; break;
964 case 11: pRate->pfnResample = audioMixBufResample11ChGeneric; break;
965 case 12: pRate->pfnResample = audioMixBufResample12ChGeneric; break;
966 default:
967 AssertMsgFailedReturn(("resampling %u changes is not implemented yet\n", cChannels), VERR_OUT_OF_RANGE);
968 }
969 }
970 return VINF_SUCCESS;
971}
972
973
974/**
975 * Initializes a mixing buffer.
976 *
977 * @returns VBox status code.
978 * @param pMixBuf Mixing buffer to initialize.
979 * @param pszName Name of mixing buffer for easier identification. Optional.
980 * @param pProps PCM audio properties to use for the mixing buffer.
981 * @param cFrames Maximum number of audio frames the mixing buffer can hold.
982 */
983int AudioMixBufInit(PAUDIOMIXBUF pMixBuf, const char *pszName, PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
984{
985 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
986 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
987 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
988 Assert(PDMAudioPropsAreValid(pProps));
989
990 /*
991 * Initialize all members, setting the volume to max (0dB).
992 */
993 pMixBuf->cFrames = 0;
994 pMixBuf->pi32Samples = NULL;
995 pMixBuf->cChannels = 0;
996 pMixBuf->cbFrame = 0;
997 pMixBuf->offRead = 0;
998 pMixBuf->offWrite = 0;
999 pMixBuf->cUsed = 0;
1000 pMixBuf->Props = *pProps;
1001 pMixBuf->Volume.fMuted = false;
1002 pMixBuf->Volume.fAllMax = true;
1003 for (uintptr_t i = 0; i < RT_ELEMENTS(pMixBuf->Volume.auChannels); i++)
1004 pMixBuf->Volume.auChannels[i] = AUDIOMIXBUF_VOL_0DB;
1005
1006 int rc;
1007 uint8_t const cChannels = PDMAudioPropsChannels(pProps);
1008 if (cChannels >= 1 && cChannels <= PDMAUDIO_MAX_CHANNELS)
1009 {
1010 pMixBuf->pszName = RTStrDup(pszName);
1011 if (pMixBuf->pszName)
1012 {
1013 pMixBuf->pi32Samples = (int32_t *)RTMemAllocZ(cFrames * cChannels * sizeof(pMixBuf->pi32Samples[0]));
1014 if (pMixBuf->pi32Samples)
1015 {
1016 pMixBuf->cFrames = cFrames;
1017 pMixBuf->cChannels = cChannels;
1018 pMixBuf->cbFrame = cChannels * sizeof(pMixBuf->pi32Samples[0]);
1019 pMixBuf->uMagic = AUDIOMIXBUF_MAGIC;
1020#ifdef AUDMIXBUF_LOG_ENABLED
1021 char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
1022 AUDMIXBUF_LOG(("%s: %s - cFrames=%#x (%d)\n",
1023 pMixBuf->pszName, PDMAudioPropsToString(pProps, szTmp, sizeof(szTmp)), cFrames, cFrames));
1024#endif
1025 return VINF_SUCCESS;
1026 }
1027 RTStrFree(pMixBuf->pszName);
1028 pMixBuf->pszName = NULL;
1029 rc = VERR_NO_MEMORY;
1030 }
1031 else
1032 rc = VERR_NO_STR_MEMORY;
1033 }
1034 else
1035 {
1036 LogRelMaxFunc(64, ("cChannels=%d pszName=%s\n", cChannels, pszName));
1037 rc = VERR_OUT_OF_RANGE;
1038 }
1039 pMixBuf->uMagic = AUDIOMIXBUF_MAGIC_DEAD;
1040 return rc;
1041}
1042
1043/**
1044 * Terminates (uninitializes) a mixing buffer.
1045 *
1046 * @param pMixBuf The mixing buffer. Uninitialized mixer buffers will be
1047 * quietly ignored. As will NULL.
1048 */
1049void AudioMixBufTerm(PAUDIOMIXBUF pMixBuf)
1050{
1051 if (!pMixBuf)
1052 return;
1053
1054 /* Ignore calls for an uninitialized (zeroed) or already destroyed instance. Happens a lot. */
1055 if ( pMixBuf->uMagic == 0
1056 || pMixBuf->uMagic == AUDIOMIXBUF_MAGIC_DEAD)
1057 {
1058 Assert(!pMixBuf->pszName);
1059 Assert(!pMixBuf->pi32Samples);
1060 Assert(!pMixBuf->cFrames);
1061 return;
1062 }
1063
1064 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1065 pMixBuf->uMagic = ~AUDIOMIXBUF_MAGIC;
1066
1067 if (pMixBuf->pszName)
1068 {
1069 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1070
1071 RTStrFree(pMixBuf->pszName);
1072 pMixBuf->pszName = NULL;
1073 }
1074
1075 if (pMixBuf->pi32Samples)
1076 {
1077 Assert(pMixBuf->cFrames);
1078 RTMemFree(pMixBuf->pi32Samples);
1079 pMixBuf->pi32Samples = NULL;
1080 }
1081
1082 pMixBuf->cFrames = 0;
1083 pMixBuf->cChannels = 0;
1084}
1085
1086
1087/**
1088 * Drops all the frames in the given mixing buffer
1089 *
1090 * This will reset the read and write offsets to zero.
1091 *
1092 * @param pMixBuf The mixing buffer. Uninitialized mixer buffers will be
1093 * quietly ignored.
1094 */
1095void AudioMixBufDrop(PAUDIOMIXBUF pMixBuf)
1096{
1097 AssertPtrReturnVoid(pMixBuf);
1098
1099 /* Ignore uninitialized (zeroed) mixer sink buffers (happens with AC'97 during VM construction). */
1100 if ( pMixBuf->uMagic == 0
1101 || pMixBuf->uMagic == AUDIOMIXBUF_MAGIC_DEAD)
1102 return;
1103
1104 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1105
1106 pMixBuf->offRead = 0;
1107 pMixBuf->offWrite = 0;
1108 pMixBuf->cUsed = 0;
1109}
1110
1111
1112/**
1113 * Gets the maximum number of audio frames this buffer can hold.
1114 *
1115 * @returns Number of frames.
1116 * @param pMixBuf The mixing buffer.
1117 */
1118uint32_t AudioMixBufSize(PCAUDIOMIXBUF pMixBuf)
1119{
1120 AssertPtrReturn(pMixBuf, 0);
1121 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1122 return pMixBuf->cFrames;
1123}
1124
1125
1126/**
1127 * Gets the maximum number of bytes this buffer can hold.
1128 *
1129 * @returns Number of bytes.
1130 * @param pMixBuf The mixing buffer.
1131 */
1132uint32_t AudioMixBufSizeBytes(PCAUDIOMIXBUF pMixBuf)
1133{
1134 AssertPtrReturn(pMixBuf, 0);
1135 AssertReturn(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC, 0);
1136 return AUDIOMIXBUF_F2B(pMixBuf, pMixBuf->cFrames);
1137}
1138
1139
1140/**
1141 * Worker for AudioMixBufUsed and AudioMixBufUsedBytes.
1142 */
1143DECLINLINE(uint32_t) audioMixBufUsedInternal(PCAUDIOMIXBUF pMixBuf)
1144{
1145 uint32_t const cFrames = pMixBuf->cFrames;
1146 uint32_t cUsed = pMixBuf->cUsed;
1147 AssertStmt(cUsed <= cFrames, cUsed = cFrames);
1148 return cUsed;
1149}
1150
1151
1152/**
1153 * Get the number of used (readable) frames in the buffer.
1154 *
1155 * @returns Number of frames.
1156 * @param pMixBuf The mixing buffer.
1157 */
1158uint32_t AudioMixBufUsed(PCAUDIOMIXBUF pMixBuf)
1159{
1160 AssertPtrReturn(pMixBuf, 0);
1161 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1162 return audioMixBufUsedInternal(pMixBuf);
1163}
1164
1165
1166/**
1167 * Get the number of (readable) bytes in the buffer.
1168 *
1169 * @returns Number of bytes.
1170 * @param pMixBuf The mixing buffer.
1171 */
1172uint32_t AudioMixBufUsedBytes(PCAUDIOMIXBUF pMixBuf)
1173{
1174 AssertPtrReturn(pMixBuf, 0);
1175 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1176 return AUDIOMIXBUF_F2B(pMixBuf, audioMixBufUsedInternal(pMixBuf));
1177}
1178
1179
1180/**
1181 * Worker for AudioMixBufFree and AudioMixBufFreeBytes.
1182 */
1183DECLINLINE(uint32_t) audioMixBufFreeInternal(PCAUDIOMIXBUF pMixBuf)
1184{
1185 uint32_t const cFrames = pMixBuf->cFrames;
1186 uint32_t cUsed = pMixBuf->cUsed;
1187 AssertStmt(cUsed <= cFrames, cUsed = cFrames);
1188 uint32_t const cFramesFree = cFrames - cUsed;
1189
1190 AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cFramesFree, cFrames));
1191 return cFramesFree;
1192}
1193
1194
1195/**
1196 * Gets the free buffer space in frames.
1197 *
1198 * @return Number of frames.
1199 * @param pMixBuf The mixing buffer.
1200 */
1201uint32_t AudioMixBufFree(PCAUDIOMIXBUF pMixBuf)
1202{
1203 AssertPtrReturn(pMixBuf, 0);
1204 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1205 return audioMixBufFreeInternal(pMixBuf);
1206}
1207
1208
1209/**
1210 * Gets the free buffer space in bytes.
1211 *
1212 * @return Number of bytes.
1213 * @param pMixBuf The mixing buffer.
1214 */
1215uint32_t AudioMixBufFreeBytes(PCAUDIOMIXBUF pMixBuf)
1216{
1217 AssertPtrReturn(pMixBuf, 0);
1218 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1219 return AUDIOMIXBUF_F2B(pMixBuf, audioMixBufFreeInternal(pMixBuf));
1220}
1221
1222
1223/**
1224 * Checks if the buffer is empty.
1225 *
1226 * @retval true if empty buffer.
1227 * @retval false if not empty and there are frames to be processed.
1228 * @param pMixBuf The mixing buffer.
1229 */
1230bool AudioMixBufIsEmpty(PCAUDIOMIXBUF pMixBuf)
1231{
1232 AssertPtrReturn(pMixBuf, true);
1233 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1234 return pMixBuf->cUsed == 0;
1235}
1236
1237
1238/**
1239 * Get the current read position.
1240 *
1241 * This is for the testcase.
1242 *
1243 * @returns Frame number.
1244 * @param pMixBuf The mixing buffer.
1245 */
1246uint32_t AudioMixBufReadPos(PCAUDIOMIXBUF pMixBuf)
1247{
1248 AssertPtrReturn(pMixBuf, 0);
1249 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1250 return pMixBuf->offRead;
1251}
1252
1253
1254/**
1255 * Gets the current write position.
1256 *
1257 * This is for the testcase.
1258 *
1259 * @returns Frame number.
1260 * @param pMixBuf The mixing buffer.
1261 */
1262uint32_t AudioMixBufWritePos(PCAUDIOMIXBUF pMixBuf)
1263{
1264 AssertPtrReturn(pMixBuf, 0);
1265 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1266 return pMixBuf->offWrite;
1267}
1268
1269
1270/**
1271 * Creates a mapping between desination channels and source source channels.
1272 *
1273 * @param paidxChannelMap Where to store the mapping. Indexed by
1274 * destination channel. Entry is either source
1275 * channel index or -1 for zero and -2 for silence.
1276 * @param pSrcProps The source properties.
1277 * @param pDstProps The desination properties.
1278 */
1279static void audioMixBufInitChannelMap(int8_t paidxChannelMap[PDMAUDIO_MAX_CHANNELS],
1280 PCPDMAUDIOPCMPROPS pSrcProps, PCPDMAUDIOPCMPROPS pDstProps)
1281{
1282 uintptr_t const cDstChannels = PDMAudioPropsChannels(pDstProps);
1283 uintptr_t const cSrcChannels = PDMAudioPropsChannels(pSrcProps);
1284 uintptr_t idxDst;
1285 for (idxDst = 0; idxDst < cDstChannels; idxDst++)
1286 {
1287 uint8_t const idDstCh = pDstProps->aidChannels[idxDst];
1288 if (idDstCh >= PDMAUDIOCHANNELID_FRONT_LEFT && idDstCh < PDMAUDIOCHANNELID_END)
1289 {
1290 uintptr_t idxSrc;
1291 for (idxSrc = 0; idxSrc < cSrcChannels; idxSrc++)
1292 if (idDstCh == pSrcProps->aidChannels[idxSrc])
1293 {
1294 paidxChannelMap[idxDst] = idxSrc;
1295 break;
1296 }
1297 if (idxSrc >= cSrcChannels)
1298 {
1299 /** @todo deal with mono. */
1300 paidxChannelMap[idxDst] = -2;
1301 }
1302 }
1303 else if (idDstCh == PDMAUDIOCHANNELID_UNKNOWN)
1304 {
1305 /** @todo What to do here? Pick unused source channels in order? */
1306 paidxChannelMap[idxDst] = -2;
1307 }
1308 else
1309 {
1310 AssertMsg(idDstCh == PDMAUDIOCHANNELID_UNUSED_SILENCE || idDstCh == PDMAUDIOCHANNELID_UNUSED_ZERO,
1311 ("idxDst=%u idDstCh=%u\n", idxDst, idDstCh));
1312 paidxChannelMap[idxDst] = idDstCh == PDMAUDIOCHANNELID_UNUSED_SILENCE ? -2 : -1;
1313 }
1314 }
1315
1316 /* Set the remainder to -1 just to be sure their are safe. */
1317 for (; idxDst < PDMAUDIO_MAX_CHANNELS; idxDst++)
1318 paidxChannelMap[idxDst] = -1;
1319}
1320
1321
1322/**
1323 * Initializes the peek state, setting up encoder and (if necessary) resampling.
1324 *
1325 * @returns VBox status code.
1326 */
1327int AudioMixBufInitPeekState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFPEEKSTATE pState, PCPDMAUDIOPCMPROPS pProps)
1328{
1329 AssertPtr(pMixBuf);
1330 AssertPtr(pState);
1331 AssertPtr(pProps);
1332
1333 /*
1334 * Pick the encoding function first.
1335 */
1336 uint8_t const cbSample = PDMAudioPropsSampleSize(pProps);
1337 uint8_t const cSrcCh = PDMAudioPropsChannels(&pMixBuf->Props);
1338 uint8_t const cDstCh = PDMAudioPropsChannels(pProps);
1339 pState->cSrcChannels = cSrcCh;
1340 pState->cDstChannels = cDstCh;
1341 pState->cbDstFrame = PDMAudioPropsFrameSize(pProps);
1342 audioMixBufInitChannelMap(pState->aidxChannelMap, &pMixBuf->Props, pProps);
1343 AssertReturn(cDstCh > 0 && cDstCh < PDMAUDIO_MAX_CHANNELS, VERR_OUT_OF_RANGE);
1344 AssertReturn(cSrcCh > 0 && cSrcCh < PDMAUDIO_MAX_CHANNELS, VERR_OUT_OF_RANGE);
1345
1346 if (PDMAudioPropsIsSigned(pProps))
1347 {
1348 /* Assign generic encoder first. */
1349 switch (cbSample)
1350 {
1351 case 1: pState->pfnEncode = audioMixBufEncodeGenericS8; break;
1352 case 2: pState->pfnEncode = audioMixBufEncodeGenericS16; break;
1353 case 4: pState->pfnEncode = audioMixBufEncodeGenericS32; break;
1354 case 8:
1355 AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
1356 pState->pfnEncode = audioMixBufEncodeGenericRaw;
1357 break;
1358 default:
1359 AssertMsgFailedReturn(("%u bytes\n", cbSample), VERR_OUT_OF_RANGE);
1360 }
1361
1362 /* Any specializations available? */
1363 switch (cDstCh)
1364 {
1365 case 1:
1366 if (cSrcCh == 1)
1367 switch (cbSample)
1368 {
1369 case 1: pState->pfnEncode = audioMixBufEncode1ChTo1ChS8; break;
1370 case 2: pState->pfnEncode = audioMixBufEncode1ChTo1ChS16; break;
1371 case 4: pState->pfnEncode = audioMixBufEncode1ChTo1ChS32; break;
1372 case 8: pState->pfnEncode = audioMixBufEncode1ChTo1ChRaw; break;
1373 }
1374 else if (cSrcCh == 2)
1375 switch (cbSample)
1376 {
1377 case 1: pState->pfnEncode = audioMixBufEncode2ChTo1ChS8; break;
1378 case 2: pState->pfnEncode = audioMixBufEncode2ChTo1ChS16; break;
1379 case 4: pState->pfnEncode = audioMixBufEncode2ChTo1ChS32; break;
1380 case 8: pState->pfnEncode = audioMixBufEncode2ChTo1ChRaw; break;
1381 }
1382 break;
1383
1384 case 2:
1385 if (cSrcCh == 1)
1386 switch (cbSample)
1387 {
1388 case 1: pState->pfnEncode = audioMixBufEncode1ChTo2ChS8; break;
1389 case 2: pState->pfnEncode = audioMixBufEncode1ChTo2ChS16; break;
1390 case 4: pState->pfnEncode = audioMixBufEncode1ChTo2ChS32; break;
1391 case 8: pState->pfnEncode = audioMixBufEncode1ChTo2ChRaw; break;
1392 }
1393 else if (cSrcCh == 2)
1394 switch (cbSample)
1395 {
1396 case 1: pState->pfnEncode = audioMixBufEncode2ChTo2ChS8; break;
1397 case 2: pState->pfnEncode = audioMixBufEncode2ChTo2ChS16; break;
1398 case 4: pState->pfnEncode = audioMixBufEncode2ChTo2ChS32; break;
1399 case 8: pState->pfnEncode = audioMixBufEncode2ChTo2ChRaw; break;
1400 }
1401 break;
1402 }
1403 }
1404 else
1405 {
1406 /* Assign generic encoder first. */
1407 switch (cbSample)
1408 {
1409 case 1: pState->pfnEncode = audioMixBufEncodeGenericU8; break;
1410 case 2: pState->pfnEncode = audioMixBufEncodeGenericU16; break;
1411 case 4: pState->pfnEncode = audioMixBufEncodeGenericU32; break;
1412 default:
1413 AssertMsgFailedReturn(("%u bytes\n", cbSample), VERR_OUT_OF_RANGE);
1414 }
1415
1416 /* Any specializations available? */
1417 switch (cDstCh)
1418 {
1419 case 1:
1420 if (cSrcCh == 1)
1421 switch (cbSample)
1422 {
1423 case 1: pState->pfnEncode = audioMixBufEncode1ChTo1ChU8; break;
1424 case 2: pState->pfnEncode = audioMixBufEncode1ChTo1ChU16; break;
1425 case 4: pState->pfnEncode = audioMixBufEncode1ChTo1ChU32; break;
1426 }
1427 else if (cSrcCh == 2)
1428 switch (cbSample)
1429 {
1430 case 1: pState->pfnEncode = audioMixBufEncode2ChTo1ChU8; break;
1431 case 2: pState->pfnEncode = audioMixBufEncode2ChTo1ChU16; break;
1432 case 4: pState->pfnEncode = audioMixBufEncode2ChTo1ChU32; break;
1433 }
1434 break;
1435
1436 case 2:
1437 if (cSrcCh == 1)
1438 switch (cbSample)
1439 {
1440 case 1: pState->pfnEncode = audioMixBufEncode1ChTo2ChU8; break;
1441 case 2: pState->pfnEncode = audioMixBufEncode1ChTo2ChU16; break;
1442 case 4: pState->pfnEncode = audioMixBufEncode1ChTo2ChU32; break;
1443 }
1444 else if (cSrcCh == 2)
1445 switch (cbSample)
1446 {
1447 case 1: pState->pfnEncode = audioMixBufEncode2ChTo2ChU8; break;
1448 case 2: pState->pfnEncode = audioMixBufEncode2ChTo2ChU16; break;
1449 case 4: pState->pfnEncode = audioMixBufEncode2ChTo2ChU32; break;
1450 }
1451 break;
1452 }
1453 }
1454
1455 int rc = audioMixBufRateInit(&pState->Rate, PDMAudioPropsHz(&pMixBuf->Props), PDMAudioPropsHz(pProps), cSrcCh);
1456 AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, PDMAudioPropsHz(&pMixBuf->Props),
1457 PDMAudioPropsHz(pProps), pState->Rate.uDstInc));
1458 return rc;
1459}
1460
1461
1462/**
1463 * Initializes the write/blend state, setting up decoders and (if necessary)
1464 * resampling.
1465 *
1466 * @returns VBox status code.
1467 */
1468int AudioMixBufInitWriteState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, PCPDMAUDIOPCMPROPS pProps)
1469{
1470 AssertPtr(pMixBuf);
1471 AssertPtr(pState);
1472 AssertPtr(pProps);
1473
1474 /*
1475 * Pick the encoding function first.
1476 */
1477 uint8_t const cbSample = PDMAudioPropsSampleSize(pProps);
1478 uint8_t const cSrcCh = PDMAudioPropsChannels(pProps);
1479 uint8_t const cDstCh = PDMAudioPropsChannels(&pMixBuf->Props);
1480 pState->cSrcChannels = cSrcCh;
1481 pState->cDstChannels = cDstCh;
1482 pState->cbSrcFrame = PDMAudioPropsFrameSize(pProps);
1483 audioMixBufInitChannelMap(pState->aidxChannelMap, pProps, &pMixBuf->Props);
1484
1485 if (PDMAudioPropsIsSigned(pProps))
1486 {
1487 /* Assign generic decoders first. */
1488 switch (cbSample)
1489 {
1490 case 1:
1491 pState->pfnDecode = audioMixBufDecodeGenericS8;
1492 pState->pfnDecodeBlend = audioMixBufDecodeGenericS8Blend;
1493 break;
1494 case 2:
1495 pState->pfnDecode = audioMixBufDecodeGenericS16;
1496 pState->pfnDecodeBlend = audioMixBufDecodeGenericS16Blend;
1497 break;
1498 case 4:
1499 pState->pfnDecode = audioMixBufDecodeGenericS32;
1500 pState->pfnDecodeBlend = audioMixBufDecodeGenericS32Blend;
1501 break;
1502 case 8:
1503 AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
1504 pState->pfnDecode = audioMixBufDecodeGenericRaw;
1505 pState->pfnDecodeBlend = audioMixBufDecodeGenericRawBlend;
1506 break;
1507 default:
1508 AssertMsgFailedReturn(("%u bytes\n", cbSample), VERR_OUT_OF_RANGE);
1509 }
1510
1511 /* Any specializations available? */
1512 switch (cDstCh)
1513 {
1514 case 1:
1515 if (cSrcCh == 1)
1516 switch (cbSample)
1517 {
1518 case 1:
1519 pState->pfnDecode = audioMixBufDecode1ChTo1ChS8;
1520 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChS8Blend;
1521 break;
1522 case 2:
1523 pState->pfnDecode = audioMixBufDecode1ChTo1ChS16;
1524 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChS16Blend;
1525 break;
1526 case 4:
1527 pState->pfnDecode = audioMixBufDecode1ChTo1ChS32;
1528 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChS32Blend;
1529 break;
1530 case 8:
1531 pState->pfnDecode = audioMixBufDecode1ChTo1ChRaw;
1532 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChRawBlend;
1533 break;
1534 }
1535 else if (cSrcCh == 2)
1536 switch (cbSample)
1537 {
1538 case 1:
1539 pState->pfnDecode = audioMixBufDecode2ChTo1ChS8;
1540 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChS8Blend;
1541 break;
1542 case 2:
1543 pState->pfnDecode = audioMixBufDecode2ChTo1ChS16;
1544 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChS16Blend;
1545 break;
1546 case 4:
1547 pState->pfnDecode = audioMixBufDecode2ChTo1ChS32;
1548 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChS32Blend;
1549 break;
1550 case 8:
1551 pState->pfnDecode = audioMixBufDecode2ChTo1ChRaw;
1552 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChRawBlend;
1553 break;
1554 }
1555 break;
1556
1557 case 2:
1558 if (cSrcCh == 1)
1559 switch (cbSample)
1560 {
1561 case 1:
1562 pState->pfnDecode = audioMixBufDecode1ChTo2ChS8;
1563 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChS8Blend;
1564 break;
1565 case 2:
1566 pState->pfnDecode = audioMixBufDecode1ChTo2ChS16;
1567 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChS16Blend;
1568 break;
1569 case 4:
1570 pState->pfnDecode = audioMixBufDecode1ChTo2ChS32;
1571 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChS32Blend;
1572 break;
1573 case 8:
1574 pState->pfnDecode = audioMixBufDecode1ChTo2ChRaw;
1575 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChRawBlend;
1576 break;
1577 }
1578 else if (cSrcCh == 2)
1579 switch (cbSample)
1580 {
1581 case 1:
1582 pState->pfnDecode = audioMixBufDecode2ChTo2ChS8;
1583 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChS8Blend;
1584 break;
1585 case 2:
1586 pState->pfnDecode = audioMixBufDecode2ChTo2ChS16;
1587 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChS16Blend;
1588 break;
1589 case 4:
1590 pState->pfnDecode = audioMixBufDecode2ChTo2ChS32;
1591 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChS32Blend;
1592 break;
1593 case 8:
1594 pState->pfnDecode = audioMixBufDecode2ChTo2ChRaw;
1595 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChRawBlend;
1596 break;
1597 }
1598 break;
1599 }
1600 }
1601 else
1602 {
1603 /* Assign generic decoders first. */
1604 switch (cbSample)
1605 {
1606 case 1:
1607 pState->pfnDecode = audioMixBufDecodeGenericU8;
1608 pState->pfnDecodeBlend = audioMixBufDecodeGenericU8Blend;
1609 break;
1610 case 2:
1611 pState->pfnDecode = audioMixBufDecodeGenericU16;
1612 pState->pfnDecodeBlend = audioMixBufDecodeGenericU16Blend;
1613 break;
1614 case 4:
1615 pState->pfnDecode = audioMixBufDecodeGenericU32;
1616 pState->pfnDecodeBlend = audioMixBufDecodeGenericU32Blend;
1617 break;
1618 default:
1619 AssertMsgFailedReturn(("%u bytes\n", cbSample), VERR_OUT_OF_RANGE);
1620 }
1621
1622 /* Any specializations available? */
1623 switch (cDstCh)
1624 {
1625 case 1:
1626 if (cSrcCh == 1)
1627 switch (cbSample)
1628 {
1629 case 1:
1630 pState->pfnDecode = audioMixBufDecode1ChTo1ChU8;
1631 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChU8Blend;
1632 break;
1633 case 2:
1634 pState->pfnDecode = audioMixBufDecode1ChTo1ChU16;
1635 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChU16Blend;
1636 break;
1637 case 4:
1638 pState->pfnDecode = audioMixBufDecode1ChTo1ChU32;
1639 pState->pfnDecodeBlend = audioMixBufDecode1ChTo1ChU32Blend;
1640 break;
1641 }
1642 else if (cSrcCh == 2)
1643 switch (cbSample)
1644 {
1645 case 1:
1646 pState->pfnDecode = audioMixBufDecode2ChTo1ChU8;
1647 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChU8Blend;
1648 break;
1649 case 2:
1650 pState->pfnDecode = audioMixBufDecode2ChTo1ChU16;
1651 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChU16Blend;
1652 break;
1653 case 4:
1654 pState->pfnDecode = audioMixBufDecode2ChTo1ChU32;
1655 pState->pfnDecodeBlend = audioMixBufDecode2ChTo1ChU32Blend;
1656 break;
1657 }
1658 break;
1659
1660 case 2:
1661 if (cSrcCh == 1)
1662 switch (cbSample)
1663 {
1664 case 1:
1665 pState->pfnDecode = audioMixBufDecode1ChTo2ChU8;
1666 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChU8Blend;
1667 break;
1668 case 2:
1669 pState->pfnDecode = audioMixBufDecode1ChTo2ChU16;
1670 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChU16Blend;
1671 break;
1672 case 4:
1673 pState->pfnDecode = audioMixBufDecode1ChTo2ChU32;
1674 pState->pfnDecodeBlend = audioMixBufDecode1ChTo2ChU32Blend;
1675 break;
1676 }
1677 else if (cSrcCh == 2)
1678 switch (cbSample)
1679 {
1680 case 1:
1681 pState->pfnDecode = audioMixBufDecode2ChTo2ChU8;
1682 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChU8Blend;
1683 break;
1684 case 2:
1685 pState->pfnDecode = audioMixBufDecode2ChTo2ChU16;
1686 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChU16Blend;
1687 break;
1688 case 4:
1689 pState->pfnDecode = audioMixBufDecode2ChTo2ChU32;
1690 pState->pfnDecodeBlend = audioMixBufDecode2ChTo2ChU32Blend;
1691 break;
1692 }
1693 break;
1694 }
1695 }
1696
1697 int rc = audioMixBufRateInit(&pState->Rate, PDMAudioPropsHz(pProps), PDMAudioPropsHz(&pMixBuf->Props), cDstCh);
1698 AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, PDMAudioPropsHz(pProps),
1699 PDMAudioPropsHz(&pMixBuf->Props), pState->Rate.uDstInc));
1700 return rc;
1701}
1702
1703
1704/**
1705 * Worker for AudioMixBufPeek that handles the rate conversion case.
1706 */
1707DECL_NO_INLINE(static, void)
1708AudioMixBufPeekResampling(PCAUDIOMIXBUF pMixBuf, uint32_t offSrcFrame, uint32_t cMaxSrcFrames, uint32_t *pcSrcFramesPeeked,
1709 PAUDIOMIXBUFPEEKSTATE pState, void *pvDst, uint32_t cbDst, uint32_t *pcbDstPeeked)
1710{
1711 *pcSrcFramesPeeked = 0;
1712 *pcbDstPeeked = 0;
1713 while (cMaxSrcFrames > 0 && cbDst >= pState->cbDstFrame)
1714 {
1715 /* Rate conversion into temporary buffer. */
1716 int32_t ai32DstRate[1024];
1717 uint32_t cSrcFrames = RT_MIN(pMixBuf->cFrames - offSrcFrame, cMaxSrcFrames);
1718 uint32_t cMaxDstFrames = RT_MIN(RT_ELEMENTS(ai32DstRate) / pState->cDstChannels, cbDst / pState->cbDstFrame);
1719 uint32_t const cDstFrames = pState->Rate.pfnResample(ai32DstRate, cMaxDstFrames,
1720 &pMixBuf->pi32Samples[offSrcFrame * pMixBuf->cChannels],
1721 cSrcFrames, &cSrcFrames, &pState->Rate);
1722 *pcSrcFramesPeeked += cSrcFrames;
1723 cMaxSrcFrames -= cSrcFrames;
1724 offSrcFrame = (offSrcFrame + cSrcFrames) % pMixBuf->cFrames;
1725
1726 /* Encode the converted frames. */
1727 uint32_t const cbDstEncoded = cDstFrames * pState->cbDstFrame;
1728 pState->pfnEncode(pvDst, ai32DstRate, cDstFrames, pState);
1729 *pcbDstPeeked += cbDstEncoded;
1730 cbDst -= cbDstEncoded;
1731 pvDst = (uint8_t *)pvDst + cbDstEncoded;
1732 }
1733}
1734
1735
1736/**
1737 * Copies data out of the mixing buffer, converting it if needed, but leaves the
1738 * read offset untouched.
1739 *
1740 * @param pMixBuf The mixing buffer.
1741 * @param offSrcFrame The offset to start reading at relative to
1742 * current read position (offRead). The caller has
1743 * made sure there is at least this number of
1744 * frames available in the buffer before calling.
1745 * @param cMaxSrcFrames Maximum number of frames to read.
1746 * @param pcSrcFramesPeeked Where to return the actual number of frames read
1747 * from the mixing buffer.
1748 * @param pState Output configuration & conversion state.
1749 * @param pvDst The destination buffer.
1750 * @param cbDst The size of the destination buffer in bytes.
1751 * @param pcbDstPeeked Where to put the actual number of bytes
1752 * returned.
1753 */
1754void AudioMixBufPeek(PCAUDIOMIXBUF pMixBuf, uint32_t offSrcFrame, uint32_t cMaxSrcFrames, uint32_t *pcSrcFramesPeeked,
1755 PAUDIOMIXBUFPEEKSTATE pState, void *pvDst, uint32_t cbDst, uint32_t *pcbDstPeeked)
1756{
1757 /*
1758 * Check inputs.
1759 */
1760 AssertPtr(pMixBuf);
1761 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1762 AssertPtr(pState);
1763 AssertPtr(pState->pfnEncode);
1764 Assert(pState->cSrcChannels == PDMAudioPropsChannels(&pMixBuf->Props));
1765 Assert(cMaxSrcFrames > 0);
1766 Assert(cMaxSrcFrames <= pMixBuf->cFrames);
1767 Assert(offSrcFrame <= pMixBuf->cFrames);
1768 Assert(offSrcFrame + cMaxSrcFrames <= pMixBuf->cUsed);
1769 AssertPtr(pcSrcFramesPeeked);
1770 AssertPtr(pvDst);
1771 Assert(cbDst >= pState->cbDstFrame);
1772 AssertPtr(pcbDstPeeked);
1773
1774 /*
1775 * Make start frame absolute.
1776 */
1777 offSrcFrame = (pMixBuf->offRead + offSrcFrame) % pMixBuf->cFrames;
1778
1779 /*
1780 * Hopefully no sample rate conversion is necessary...
1781 */
1782 if (pState->Rate.fNoConversionNeeded)
1783 {
1784 /* Figure out how much we should convert. */
1785 cMaxSrcFrames = RT_MIN(cMaxSrcFrames, cbDst / pState->cbDstFrame);
1786 *pcSrcFramesPeeked = cMaxSrcFrames;
1787 *pcbDstPeeked = cMaxSrcFrames * pState->cbDstFrame;
1788
1789 /* First chunk. */
1790 uint32_t const cSrcFrames1 = RT_MIN(pMixBuf->cFrames - offSrcFrame, cMaxSrcFrames);
1791 pState->pfnEncode(pvDst, &pMixBuf->pi32Samples[offSrcFrame * pMixBuf->cChannels], cSrcFrames1, pState);
1792
1793 /* Another chunk from the start of the mixing buffer? */
1794 if (cMaxSrcFrames > cSrcFrames1)
1795 pState->pfnEncode((uint8_t *)pvDst + cSrcFrames1 * pState->cbDstFrame,
1796 &pMixBuf->pi32Samples[0], cMaxSrcFrames - cSrcFrames1, pState);
1797 }
1798 else
1799 AudioMixBufPeekResampling(pMixBuf, offSrcFrame, cMaxSrcFrames, pcSrcFramesPeeked, pState, pvDst, cbDst, pcbDstPeeked);
1800}
1801
1802
1803/**
1804 * Worker for AudioMixBufWrite that handles the rate conversion case.
1805 */
1806DECL_NO_INLINE(static, void)
1807audioMixBufWriteResampling(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
1808 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten)
1809{
1810 *pcDstFramesWritten = 0;
1811 while (cMaxDstFrames > 0 && cbSrcBuf >= pState->cbSrcFrame)
1812 {
1813 /* Decode into temporary buffer. */
1814 int32_t ai32SrcDecoded[1024];
1815 uint32_t cFramesDecoded = RT_MIN(RT_ELEMENTS(ai32SrcDecoded) / pState->cSrcChannels, cbSrcBuf / pState->cbSrcFrame);
1816 pState->pfnDecode(ai32SrcDecoded, pvSrcBuf, cFramesDecoded, pState);
1817 cbSrcBuf -= cFramesDecoded * pState->cbSrcFrame;
1818 pvSrcBuf = (uint8_t const *)pvSrcBuf + cFramesDecoded * pState->cbSrcFrame;
1819
1820 /* Rate convert that into the mixer. */
1821 uint32_t iFrameDecoded = 0;
1822 while (iFrameDecoded < cFramesDecoded)
1823 {
1824 uint32_t cDstMaxFrames = RT_MIN(pMixBuf->cFrames - offDstFrame, cMaxDstFrames);
1825 uint32_t cSrcFrames = cFramesDecoded - iFrameDecoded;
1826 uint32_t const cDstFrames = pState->Rate.pfnResample(&pMixBuf->pi32Samples[offDstFrame * pMixBuf->cChannels],
1827 cDstMaxFrames,
1828 &ai32SrcDecoded[iFrameDecoded * pState->cSrcChannels],
1829 cSrcFrames, &cSrcFrames, &pState->Rate);
1830
1831 iFrameDecoded += cSrcFrames;
1832 *pcDstFramesWritten += cDstFrames;
1833 offDstFrame = (offDstFrame + cDstFrames) % pMixBuf->cFrames;
1834 }
1835 }
1836
1837 /** @todo How to squeeze odd frames out of 22050 => 44100 conversion? */
1838}
1839
1840
1841/**
1842 * Writes @a cbSrcBuf bytes to the mixer buffer starting at @a offDstFrame,
1843 * converting it as needed, leaving the write offset untouched.
1844 *
1845 * @param pMixBuf The mixing buffer.
1846 * @param pState Source configuration & conversion state.
1847 * @param pvSrcBuf The source frames.
1848 * @param cbSrcBuf Number of bytes of source frames. This will be
1849 * convered in full.
1850 * @param offDstFrame Mixing buffer offset relative to the write
1851 * position.
1852 * @param cMaxDstFrames Max number of frames to write.
1853 * @param pcDstFramesWritten Where to return the number of frames actually
1854 * written.
1855 *
1856 * @note Does not advance the write position, please call AudioMixBufCommit()
1857 * to do that.
1858 */
1859void AudioMixBufWrite(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
1860 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesWritten)
1861{
1862 /*
1863 * Check inputs.
1864 */
1865 AssertPtr(pMixBuf);
1866 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1867 AssertPtr(pState);
1868 AssertPtr(pState->pfnDecode);
1869 AssertPtr(pState->pfnDecodeBlend);
1870 Assert(pState->cDstChannels == PDMAudioPropsChannels(&pMixBuf->Props));
1871 Assert(cMaxDstFrames > 0);
1872 Assert(cMaxDstFrames <= pMixBuf->cFrames - pMixBuf->cUsed);
1873 Assert(offDstFrame <= pMixBuf->cFrames);
1874 AssertPtr(pvSrcBuf);
1875 Assert(!(cbSrcBuf % pState->cbSrcFrame));
1876 AssertPtr(pcDstFramesWritten);
1877
1878 /*
1879 * Make start frame absolute.
1880 */
1881 offDstFrame = (pMixBuf->offWrite + offDstFrame) % pMixBuf->cFrames;
1882
1883 /*
1884 * Hopefully no sample rate conversion is necessary...
1885 */
1886 if (pState->Rate.fNoConversionNeeded)
1887 {
1888 /* Figure out how much we should convert. */
1889 Assert(cMaxDstFrames >= cbSrcBuf / pState->cbSrcFrame);
1890 cMaxDstFrames = RT_MIN(cMaxDstFrames, cbSrcBuf / pState->cbSrcFrame);
1891 *pcDstFramesWritten = cMaxDstFrames;
1892
1893 /* First chunk. */
1894 uint32_t const cDstFrames1 = RT_MIN(pMixBuf->cFrames - offDstFrame, cMaxDstFrames);
1895 pState->pfnDecode(&pMixBuf->pi32Samples[offDstFrame * pMixBuf->cChannels], pvSrcBuf, cDstFrames1, pState);
1896
1897 /* Another chunk from the start of the mixing buffer? */
1898 if (cMaxDstFrames > cDstFrames1)
1899 pState->pfnDecode(&pMixBuf->pi32Samples[0], (uint8_t *)pvSrcBuf + cDstFrames1 * pState->cbSrcFrame,
1900 cMaxDstFrames - cDstFrames1, pState);
1901 }
1902 else
1903 audioMixBufWriteResampling(pMixBuf, pState, pvSrcBuf, cbSrcBuf, offDstFrame, cMaxDstFrames, pcDstFramesWritten);
1904}
1905
1906
1907/**
1908 * Worker for AudioMixBufBlend that handles the rate conversion case.
1909 */
1910DECL_NO_INLINE(static, void)
1911audioMixBufBlendResampling(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
1912 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesBlended)
1913{
1914 *pcDstFramesBlended = 0;
1915 while (cMaxDstFrames > 0 && cbSrcBuf >= pState->cbSrcFrame)
1916 {
1917 /* Decode into temporary buffer. */
1918 int32_t ai32SrcDecoded[1024];
1919 uint32_t cFramesDecoded = RT_MIN(RT_ELEMENTS(ai32SrcDecoded) / pState->cSrcChannels, cbSrcBuf / pState->cbSrcFrame);
1920 pState->pfnDecode(ai32SrcDecoded, pvSrcBuf, cFramesDecoded, pState);
1921 cbSrcBuf -= cFramesDecoded * pState->cbSrcFrame;
1922 pvSrcBuf = (uint8_t const *)pvSrcBuf + cFramesDecoded * pState->cbSrcFrame;
1923
1924 /* Rate convert that into another temporary buffer and then blend that into the mixer. */
1925 uint32_t iFrameDecoded = 0;
1926 while (iFrameDecoded < cFramesDecoded)
1927 {
1928 int32_t ai32SrcRate[1024];
1929 uint32_t cDstMaxFrames = RT_MIN(RT_ELEMENTS(ai32SrcRate), cMaxDstFrames);
1930 uint32_t cSrcFrames = cFramesDecoded - iFrameDecoded;
1931 uint32_t const cDstFrames = pState->Rate.pfnResample(&ai32SrcRate[0], cDstMaxFrames,
1932 &ai32SrcDecoded[iFrameDecoded * pState->cSrcChannels],
1933 cSrcFrames, &cSrcFrames, &pState->Rate);
1934
1935 /* First chunk.*/
1936 uint32_t const cDstFrames1 = RT_MIN(pMixBuf->cFrames - offDstFrame, cDstFrames);
1937 audioMixBufBlendBuffer(&pMixBuf->pi32Samples[offDstFrame * pMixBuf->cChannels],
1938 ai32SrcRate, cDstFrames1, pState->cSrcChannels);
1939
1940 /* Another chunk from the start of the mixing buffer? */
1941 if (cDstFrames > cDstFrames1)
1942 audioMixBufBlendBuffer(&pMixBuf->pi32Samples[0], &ai32SrcRate[cDstFrames1 * pState->cSrcChannels],
1943 cDstFrames - cDstFrames1, pState->cSrcChannels);
1944
1945 /* Advance */
1946 iFrameDecoded += cSrcFrames;
1947 *pcDstFramesBlended += cDstFrames;
1948 offDstFrame = (offDstFrame + cDstFrames) % pMixBuf->cFrames;
1949 }
1950 }
1951
1952 /** @todo How to squeeze odd frames out of 22050 => 44100 conversion? */
1953}
1954
1955
1956/**
1957 * @todo not sure if 'blend' is the appropriate term here, but you know what
1958 * we mean.
1959 */
1960void AudioMixBufBlend(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, const void *pvSrcBuf, uint32_t cbSrcBuf,
1961 uint32_t offDstFrame, uint32_t cMaxDstFrames, uint32_t *pcDstFramesBlended)
1962{
1963 /*
1964 * Check inputs.
1965 */
1966 AssertPtr(pMixBuf);
1967 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1968 AssertPtr(pState);
1969 AssertPtr(pState->pfnDecode);
1970 AssertPtr(pState->pfnDecodeBlend);
1971 Assert(pState->cDstChannels == PDMAudioPropsChannels(&pMixBuf->Props));
1972 Assert(cMaxDstFrames > 0);
1973 Assert(cMaxDstFrames <= pMixBuf->cFrames - pMixBuf->cUsed);
1974 Assert(offDstFrame <= pMixBuf->cFrames);
1975 AssertPtr(pvSrcBuf);
1976 Assert(!(cbSrcBuf % pState->cbSrcFrame));
1977 AssertPtr(pcDstFramesBlended);
1978
1979 /*
1980 * Make start frame absolute.
1981 */
1982 offDstFrame = (pMixBuf->offWrite + offDstFrame) % pMixBuf->cFrames;
1983
1984 /*
1985 * Hopefully no sample rate conversion is necessary...
1986 */
1987 if (pState->Rate.fNoConversionNeeded)
1988 {
1989 /* Figure out how much we should convert. */
1990 Assert(cMaxDstFrames >= cbSrcBuf / pState->cbSrcFrame);
1991 cMaxDstFrames = RT_MIN(cMaxDstFrames, cbSrcBuf / pState->cbSrcFrame);
1992 *pcDstFramesBlended = cMaxDstFrames;
1993
1994 /* First chunk. */
1995 uint32_t const cDstFrames1 = RT_MIN(pMixBuf->cFrames - offDstFrame, cMaxDstFrames);
1996 pState->pfnDecodeBlend(&pMixBuf->pi32Samples[offDstFrame * pMixBuf->cChannels], pvSrcBuf, cDstFrames1, pState);
1997
1998 /* Another chunk from the start of the mixing buffer? */
1999 if (cMaxDstFrames > cDstFrames1)
2000 pState->pfnDecodeBlend(&pMixBuf->pi32Samples[0], (uint8_t *)pvSrcBuf + cDstFrames1 * pState->cbSrcFrame,
2001 cMaxDstFrames - cDstFrames1, pState);
2002 }
2003 else
2004 audioMixBufBlendResampling(pMixBuf, pState, pvSrcBuf, cbSrcBuf, offDstFrame, cMaxDstFrames, pcDstFramesBlended);
2005}
2006
2007
2008/**
2009 * Writes @a cFrames of silence at @a offFrame relative to current write pos.
2010 *
2011 * This will also adjust the resampling state.
2012 *
2013 * @param pMixBuf The mixing buffer.
2014 * @param pState The write state.
2015 * @param offFrame Where to start writing silence relative to the current
2016 * write position.
2017 * @param cFrames Number of frames of silence.
2018 * @sa AudioMixBufWrite
2019 *
2020 * @note Does not advance the write position, please call AudioMixBufCommit()
2021 * to do that.
2022 */
2023void AudioMixBufSilence(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t offFrame, uint32_t cFrames)
2024{
2025 /*
2026 * Check inputs.
2027 */
2028 AssertPtr(pMixBuf);
2029 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
2030 AssertPtr(pState);
2031 AssertPtr(pState->pfnDecode);
2032 AssertPtr(pState->pfnDecodeBlend);
2033 Assert(pState->cDstChannels == PDMAudioPropsChannels(&pMixBuf->Props));
2034 Assert(cFrames > 0);
2035#ifdef VBOX_STRICT
2036 uint32_t const cMixBufFree = pMixBuf->cFrames - pMixBuf->cUsed;
2037#endif
2038 Assert(cFrames <= cMixBufFree);
2039 Assert(offFrame < cMixBufFree);
2040 Assert(offFrame + cFrames <= cMixBufFree);
2041
2042 /*
2043 * Make start frame absolute.
2044 */
2045 offFrame = (pMixBuf->offWrite + offFrame) % pMixBuf->cFrames;
2046
2047 /*
2048 * First chunk.
2049 */
2050 uint32_t const cFramesChunk1 = RT_MIN(pMixBuf->cFrames - offFrame, cFrames);
2051 RT_BZERO(&pMixBuf->pi32Samples[offFrame * pMixBuf->cChannels], cFramesChunk1 * pMixBuf->cbFrame);
2052
2053 /*
2054 * Second chunk, if needed.
2055 */
2056 if (cFrames > cFramesChunk1)
2057 {
2058 cFrames -= cFramesChunk1;
2059 AssertStmt(cFrames <= pMixBuf->cFrames, cFrames = pMixBuf->cFrames);
2060 RT_BZERO(&pMixBuf->pi32Samples[0], cFrames * pMixBuf->cbFrame);
2061 }
2062
2063 /*
2064 * Reset the resampling state.
2065 */
2066 audioMixBufRateReset(&pState->Rate);
2067}
2068
2069
2070/**
2071 * Records a blending gap (silence) of @a cFrames.
2072 *
2073 * This is used to adjust or reset the resampling state so we start from a
2074 * silence state the next time we need to blend or write using @a pState.
2075 *
2076 * @param pMixBuf The mixing buffer.
2077 * @param pState The write state.
2078 * @param cFrames Number of frames of silence.
2079 * @sa AudioMixBufSilence
2080 */
2081void AudioMixBufBlendGap(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t cFrames)
2082{
2083 /*
2084 * For now we'll just reset the resampling state regardless of how many
2085 * frames of silence there is.
2086 */
2087 audioMixBufRateReset(&pState->Rate);
2088 RT_NOREF(pMixBuf, cFrames);
2089}
2090
2091
2092/**
2093 * Advances the read position of the buffer.
2094 *
2095 * For use after done peeking with AudioMixBufPeek().
2096 *
2097 * @param pMixBuf The mixing buffer.
2098 * @param cFrames Number of frames to advance.
2099 * @sa AudioMixBufCommit
2100 */
2101void AudioMixBufAdvance(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
2102{
2103 AssertPtrReturnVoid(pMixBuf);
2104 AssertReturnVoid(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
2105
2106 AssertStmt(cFrames <= pMixBuf->cUsed, cFrames = pMixBuf->cUsed);
2107 pMixBuf->cUsed -= cFrames;
2108 pMixBuf->offRead = (pMixBuf->offRead + cFrames) % pMixBuf->cFrames;
2109 LogFlowFunc(("%s: Advanced %u frames: offRead=%u cUsed=%u\n", pMixBuf->pszName, cFrames, pMixBuf->offRead, pMixBuf->cUsed));
2110}
2111
2112
2113/**
2114 * Worker for audioMixAdjustVolume that adjust one contiguous chunk.
2115 */
2116static void audioMixAdjustVolumeWorker(PAUDIOMIXBUF pMixBuf, uint32_t off, uint32_t cFrames)
2117{
2118 int32_t *pi32Samples = &pMixBuf->pi32Samples[off * pMixBuf->cChannels];
2119 switch (pMixBuf->cChannels)
2120 {
2121 case 1:
2122 {
2123 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2124 while (cFrames-- > 0)
2125 {
2126 *pi32Samples = (int32_t)(ASMMult2xS32RetS64(*pi32Samples, uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2127 pi32Samples++;
2128 }
2129 break;
2130 }
2131
2132 case 2:
2133 {
2134 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2135 uint32_t const uFactorCh1 = pMixBuf->Volume.auChannels[1];
2136 while (cFrames-- > 0)
2137 {
2138 pi32Samples[0] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[0], uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2139 pi32Samples[1] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[1], uFactorCh1) >> AUDIOMIXBUF_VOL_SHIFT);
2140 pi32Samples += 2;
2141 }
2142 break;
2143 }
2144
2145 case 3:
2146 {
2147 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2148 uint32_t const uFactorCh1 = pMixBuf->Volume.auChannels[1];
2149 uint32_t const uFactorCh2 = pMixBuf->Volume.auChannels[2];
2150 while (cFrames-- > 0)
2151 {
2152 pi32Samples[0] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[0], uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2153 pi32Samples[1] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[1], uFactorCh1) >> AUDIOMIXBUF_VOL_SHIFT);
2154 pi32Samples[2] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[2], uFactorCh2) >> AUDIOMIXBUF_VOL_SHIFT);
2155 pi32Samples += 3;
2156 }
2157 break;
2158 }
2159
2160 case 4:
2161 {
2162 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2163 uint32_t const uFactorCh1 = pMixBuf->Volume.auChannels[1];
2164 uint32_t const uFactorCh2 = pMixBuf->Volume.auChannels[2];
2165 uint32_t const uFactorCh3 = pMixBuf->Volume.auChannels[3];
2166 while (cFrames-- > 0)
2167 {
2168 pi32Samples[0] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[0], uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2169 pi32Samples[1] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[1], uFactorCh1) >> AUDIOMIXBUF_VOL_SHIFT);
2170 pi32Samples[2] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[2], uFactorCh2) >> AUDIOMIXBUF_VOL_SHIFT);
2171 pi32Samples[3] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[3], uFactorCh3) >> AUDIOMIXBUF_VOL_SHIFT);
2172 pi32Samples += 4;
2173 }
2174 break;
2175 }
2176
2177 case 5:
2178 {
2179 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2180 uint32_t const uFactorCh1 = pMixBuf->Volume.auChannels[1];
2181 uint32_t const uFactorCh2 = pMixBuf->Volume.auChannels[2];
2182 uint32_t const uFactorCh3 = pMixBuf->Volume.auChannels[3];
2183 uint32_t const uFactorCh4 = pMixBuf->Volume.auChannels[4];
2184 while (cFrames-- > 0)
2185 {
2186 pi32Samples[0] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[0], uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2187 pi32Samples[1] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[1], uFactorCh1) >> AUDIOMIXBUF_VOL_SHIFT);
2188 pi32Samples[2] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[2], uFactorCh2) >> AUDIOMIXBUF_VOL_SHIFT);
2189 pi32Samples[3] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[3], uFactorCh3) >> AUDIOMIXBUF_VOL_SHIFT);
2190 pi32Samples[4] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[4], uFactorCh4) >> AUDIOMIXBUF_VOL_SHIFT);
2191 pi32Samples += 5;
2192 }
2193 break;
2194 }
2195
2196 case 6:
2197 {
2198 uint32_t const uFactorCh0 = pMixBuf->Volume.auChannels[0];
2199 uint32_t const uFactorCh1 = pMixBuf->Volume.auChannels[1];
2200 uint32_t const uFactorCh2 = pMixBuf->Volume.auChannels[2];
2201 uint32_t const uFactorCh3 = pMixBuf->Volume.auChannels[3];
2202 uint32_t const uFactorCh4 = pMixBuf->Volume.auChannels[4];
2203 uint32_t const uFactorCh5 = pMixBuf->Volume.auChannels[5];
2204 while (cFrames-- > 0)
2205 {
2206 pi32Samples[0] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[0], uFactorCh0) >> AUDIOMIXBUF_VOL_SHIFT);
2207 pi32Samples[1] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[1], uFactorCh1) >> AUDIOMIXBUF_VOL_SHIFT);
2208 pi32Samples[2] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[2], uFactorCh2) >> AUDIOMIXBUF_VOL_SHIFT);
2209 pi32Samples[3] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[3], uFactorCh3) >> AUDIOMIXBUF_VOL_SHIFT);
2210 pi32Samples[4] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[4], uFactorCh4) >> AUDIOMIXBUF_VOL_SHIFT);
2211 pi32Samples[5] = (int32_t)(ASMMult2xS32RetS64(pi32Samples[5], uFactorCh5) >> AUDIOMIXBUF_VOL_SHIFT);
2212 pi32Samples += 6;
2213 }
2214 break;
2215 }
2216
2217 default:
2218 while (cFrames-- > 0)
2219 for (uint32_t iCh = 0; iCh < pMixBuf->cChannels; iCh++, pi32Samples++)
2220 *pi32Samples = ASMMult2xS32RetS64(*pi32Samples, pMixBuf->Volume.auChannels[iCh]) >> AUDIOMIXBUF_VOL_SHIFT;
2221 break;
2222 }
2223}
2224
2225
2226/**
2227 * Does volume adjustments for the given stretch of the buffer.
2228 *
2229 * @param pMixBuf The mixing buffer.
2230 * @param offFirst Where to start (validated).
2231 * @param cFrames How many frames (validated).
2232 */
2233static void audioMixAdjustVolume(PAUDIOMIXBUF pMixBuf, uint32_t offFirst, uint32_t cFrames)
2234{
2235 /* Caller has already validated these, so we don't need to repeat that in non-strict builds. */
2236 Assert(offFirst < pMixBuf->cFrames);
2237 Assert(cFrames <= pMixBuf->cFrames);
2238
2239 /*
2240 * Muted?
2241 */
2242 if (pMixBuf->Volume.fMuted)
2243 {
2244 /* first chunk */
2245 uint32_t const cFramesChunk1 = RT_MIN(pMixBuf->cFrames - offFirst, cFrames);
2246 RT_BZERO(&pMixBuf->pi32Samples[offFirst * pMixBuf->cChannels], pMixBuf->cbFrame * cFramesChunk1);
2247
2248 /* second chunk */
2249 if (cFramesChunk1 < cFrames)
2250 RT_BZERO(&pMixBuf->pi32Samples[0], pMixBuf->cbFrame * (cFrames - cFramesChunk1));
2251 }
2252 /*
2253 * Less than max volume?
2254 */
2255 else if (!pMixBuf->Volume.fAllMax)
2256 {
2257 /* first chunk */
2258 uint32_t const cFramesChunk1 = RT_MIN(pMixBuf->cFrames - offFirst, cFrames);
2259 audioMixAdjustVolumeWorker(pMixBuf, offFirst, cFramesChunk1);
2260
2261 /* second chunk */
2262 if (cFramesChunk1 < cFrames)
2263 audioMixAdjustVolumeWorker(pMixBuf, 0, cFrames - cFramesChunk1);
2264 }
2265}
2266
2267
2268/**
2269 * Adjust for volume settings and advances the write position of the buffer.
2270 *
2271 * For use after done peeking with AudioMixBufWrite(), AudioMixBufSilence(),
2272 * AudioMixBufBlend() and AudioMixBufBlendGap().
2273 *
2274 * @param pMixBuf The mixing buffer.
2275 * @param cFrames Number of frames to advance.
2276 * @sa AudioMixBufAdvance, AudioMixBufSetVolume
2277 */
2278void AudioMixBufCommit(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
2279{
2280 AssertPtrReturnVoid(pMixBuf);
2281 AssertReturnVoid(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
2282
2283 AssertStmt(cFrames <= pMixBuf->cFrames - pMixBuf->cUsed, cFrames = pMixBuf->cFrames - pMixBuf->cUsed);
2284
2285 audioMixAdjustVolume(pMixBuf, pMixBuf->offWrite, cFrames);
2286
2287 pMixBuf->cUsed += cFrames;
2288 pMixBuf->offWrite = (pMixBuf->offWrite + cFrames) % pMixBuf->cFrames;
2289 LogFlowFunc(("%s: Advanced %u frames: offWrite=%u cUsed=%u\n", pMixBuf->pszName, cFrames, pMixBuf->offWrite, pMixBuf->cUsed));
2290}
2291
2292
2293/**
2294 * Sets the volume.
2295 *
2296 * The volume adjustments are applied by AudioMixBufCommit().
2297 *
2298 * @param pMixBuf Mixing buffer to set volume for.
2299 * @param pVol Pointer to volume structure to set.
2300 */
2301void AudioMixBufSetVolume(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOVOLUME pVol)
2302{
2303 AssertPtrReturnVoid(pMixBuf);
2304 AssertPtrReturnVoid(pVol);
2305
2306 LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
2307
2308 /*
2309 * Convert PDM audio volume to the internal format.
2310 */
2311 if (!pVol->fMuted)
2312 {
2313 pMixBuf->Volume.fMuted = false;
2314
2315 AssertCompileSize(pVol->uLeft, sizeof(uint8_t));
2316 pMixBuf->Volume.auChannels[0] = s_aVolumeConv[pVol->uLeft ] * (AUDIOMIXBUF_VOL_0DB >> 16);
2317 pMixBuf->Volume.auChannels[1] = s_aVolumeConv[pVol->uRight] * (AUDIOMIXBUF_VOL_0DB >> 16);
2318 for (uintptr_t i = 2; i < pMixBuf->cChannels; i++)
2319 pMixBuf->Volume.auChannels[i] = pMixBuf->Volume.auChannels[1];
2320
2321 pMixBuf->Volume.fAllMax = true;
2322 for (uintptr_t i = 0; i < pMixBuf->cChannels; i++)
2323 if (pMixBuf->Volume.auChannels[i] != AUDIOMIXBUF_VOL_0DB)
2324 {
2325 pMixBuf->Volume.fAllMax = false;
2326 break;
2327 }
2328 }
2329 else
2330 {
2331 pMixBuf->Volume.fMuted = true;
2332 pMixBuf->Volume.fAllMax = false;
2333 for (uintptr_t i = 0; i < RT_ELEMENTS(pMixBuf->Volume.auChannels); i++)
2334 pMixBuf->Volume.auChannels[i] = 0;
2335 }
2336}
2337
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette