Changeset 89395 in vbox for trunk/src/VBox/Devices
- Timestamp:
- May 31, 2021 12:31:45 PM (4 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixBuffer-Convert.cpp.h
r89394 r89395 1 1 /* $Id$ */ 2 2 /** @file 3 * Audio mixing buffer for converting reading/writing audio data.3 * Audio mixing buffer for converting template. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2014-202 0Oracle Corporation7 * Copyright (C) 2014-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 /** @page pg_audio_mix_buffer Audio Mixer Buffer19 *20 * @section sec_audio_mix_buffer_volume Soft Volume Control21 *22 * The external code supplies an 8-bit volume (attenuation) value in the23 * 0 .. 255 range. This represents 0 to -96dB attenuation where an input24 * 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-bit30 * (sort of) exponential value between 1 and 65536. This is used with fixed31 * 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 (or34 * unattenuated) volume is represented as 0x40000000; conveniently, this35 * value fits into a uint32_t.36 *37 * To enable fast processing, the maximum volume must be a power of two38 * and must not have a sign when converted to int32_t. While 0x8000000039 * violates these constraints, 0x40000000 does not.40 */41 42 43 /*********************************************************************************************************************************44 * Header Files *45 *********************************************************************************************************************************/46 #define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER47 #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 #endif50 #include <VBox/log.h>51 52 #if 053 /*54 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data55 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH56 * to your needs before using this!57 */58 # define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA59 # ifdef RT_OS_WINDOWS60 # define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"61 # else62 # define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"63 # endif64 /* Warning: Enabling this will generate *huge* logs! */65 //# define AUDIOMIXBUF_DEBUG_MACROS66 #endif67 68 #include <iprt/asm-math.h>69 #include <iprt/assert.h>70 #ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA71 # include <iprt/file.h>72 #endif73 #include <iprt/mem.h>74 #include <iprt/string.h> /* For RT_BZERO. */75 76 #ifdef VBOX_AUDIO_TESTCASE77 # define LOG_ENABLED78 # include <iprt/stream.h>79 #endif80 #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_TESTCASE90 # ifdef DEBUG91 # define AUDMIXBUF_LOG(x) LogFlowFunc(x)92 # define AUDMIXBUF_LOG_ENABLED93 # else94 # define AUDMIXBUF_LOG(x) do {} while (0)95 # endif96 #else /* VBOX_AUDIO_TESTCASE */97 # define AUDMIXBUF_LOG(x) RTPrintf x98 # define AUDMIXBUF_LOG_ENABLED99 #endif100 101 102 /** Bit shift for fixed point conversion.103 * @sa @ref sec_audio_mix_buffer_volume */104 #define AUDIOMIXBUF_VOL_SHIFT 30105 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)109 AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */110 AssertCompile(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_volume118 */119 static 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_STRICT158 # ifdef UNUSED159 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 */169 static 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 176 static 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 */187 static 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 */228 DECL_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 else236 *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 */246 DECL_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 */268 static 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_MACROS298 # 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 x301 #else302 # define AUDMIXBUF_MACRO_LOG(x) do {} while (0)303 #endif304 18 305 19 /** … … 587 301 } 588 302 589 590 /* audioMixBufConvXXXS8: 8-bit, signed. */591 AUDMIXBUF_CONVERT(S8 /* Name */, int8_t, INT8_MIN /* Min */, INT8_MAX /* Max */, true /* fSigned */, 8 /* cShift */)592 /* audioMixBufConvXXXU8: 8-bit, unsigned. */593 AUDMIXBUF_CONVERT(U8 /* Name */, uint8_t, 0 /* Min */, UINT8_MAX /* Max */, false /* fSigned */, 8 /* cShift */)594 /* audioMixBufConvXXXS16: 16-bit, signed. */595 AUDMIXBUF_CONVERT(S16 /* Name */, int16_t, INT16_MIN /* Min */, INT16_MAX /* Max */, true /* fSigned */, 16 /* cShift */)596 /* audioMixBufConvXXXU16: 16-bit, unsigned. */597 AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0 /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)598 /* audioMixBufConvXXXS32: 32-bit, signed. */599 AUDMIXBUF_CONVERT(S32 /* Name */, int32_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)600 /* audioMixBufConvXXXU32: 32-bit, unsigned. */601 AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)602 /* audioMixBufConvXXXRaw: 32-bit stored as 64-bit, signed. */603 AUDMIXBUF_CONVERT(Raw /* Name */, int64_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)604 605 #undef AUDMIXBUF_CONVERT606 #undef AUDMIXBUF_MACRO_LOG607 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) >> 32718 #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 874 AUDIOMIXBUF_RESAMPLE(1,Generic)875 AUDIOMIXBUF_RESAMPLE(2,Generic)876 AUDIOMIXBUF_RESAMPLE(3,Generic)877 AUDIOMIXBUF_RESAMPLE(4,Generic)878 AUDIOMIXBUF_RESAMPLE(5,Generic)879 AUDIOMIXBUF_RESAMPLE(6,Generic)880 AUDIOMIXBUF_RESAMPLE(7,Generic)881 AUDIOMIXBUF_RESAMPLE(8,Generic)882 AUDIOMIXBUF_RESAMPLE(9,Generic)883 AUDIOMIXBUF_RESAMPLE(10,Generic)884 AUDIOMIXBUF_RESAMPLE(11,Generic)885 AUDIOMIXBUF_RESAMPLE(12,Generic)886 887 888 /**889 * Resets the resampling state unconditionally.890 *891 * @param pRate The state to reset.892 */893 static 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 */907 DECLINLINE(void) audioMixBufRateReset(PAUDIOSTREAMRATE pRate)908 {909 if (pRate->offDst == 0)910 { /* likely */ }911 else912 {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 */928 DECLINLINE(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 else948 {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 */983 int 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_ENABLED1021 char szTmp[PDMAUDIOPROPSTOSTRING_MAX];1022 AUDMIXBUF_LOG(("%s: %s - cFrames=%#x (%d)\n",1023 pMixBuf->pszName, PDMAudioPropsToString(pProps, szTmp, sizeof(szTmp)), cFrames, cFrames));1024 #endif1025 return VINF_SUCCESS;1026 }1027 RTStrFree(pMixBuf->pszName);1028 pMixBuf->pszName = NULL;1029 rc = VERR_NO_MEMORY;1030 }1031 else1032 rc = VERR_NO_STR_MEMORY;1033 }1034 else1035 {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 be1047 * quietly ignored. As will NULL.1048 */1049 void 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 == 01056 || 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 buffer1089 *1090 * This will reset the read and write offsets to zero.1091 *1092 * @param pMixBuf The mixing buffer. Uninitialized mixer buffers will be1093 * quietly ignored.1094 */1095 void 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 == 01101 || 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 */1118 uint32_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 */1132 uint32_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 */1143 DECLINLINE(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 */1158 uint32_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 */1172 uint32_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 */1183 DECLINLINE(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 */1201 uint32_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 */1215 uint32_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 */1230 bool 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 */1246 uint32_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 */1262 uint32_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 by1274 * destination channel. Entry is either source1275 * channel index or -1 for zero and -2 for silence.1276 * @param pSrcProps The source properties.1277 * @param pDstProps The desination properties.1278 */1279 static 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 else1309 {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 */1327 int 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 else1405 {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 */1468 int 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 else1602 {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 */1707 DECL_NO_INLINE(static, void)1708 AudioMixBufPeekResampling(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 the1738 * read offset untouched.1739 *1740 * @param pMixBuf The mixing buffer.1741 * @param offSrcFrame The offset to start reading at relative to1742 * current read position (offRead). The caller has1743 * made sure there is at least this number of1744 * 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 read1747 * 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 bytes1752 * returned.1753 */1754 void 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 else1799 AudioMixBufPeekResampling(pMixBuf, offSrcFrame, cMaxSrcFrames, pcSrcFramesPeeked, pState, pvDst, cbDst, pcbDstPeeked);1800 }1801 1802 1803 /**1804 * Worker for AudioMixBufWrite that handles the rate conversion case.1805 */1806 DECL_NO_INLINE(static, void)1807 audioMixBufWriteResampling(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 be1849 * convered in full.1850 * @param offDstFrame Mixing buffer offset relative to the write1851 * position.1852 * @param cMaxDstFrames Max number of frames to write.1853 * @param pcDstFramesWritten Where to return the number of frames actually1854 * written.1855 *1856 * @note Does not advance the write position, please call AudioMixBufCommit()1857 * to do that.1858 */1859 void 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 else1903 audioMixBufWriteResampling(pMixBuf, pState, pvSrcBuf, cbSrcBuf, offDstFrame, cMaxDstFrames, pcDstFramesWritten);1904 }1905 1906 1907 /**1908 * Worker for AudioMixBufBlend that handles the rate conversion case.1909 */1910 DECL_NO_INLINE(static, void)1911 audioMixBufBlendResampling(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 what1958 * we mean.1959 */1960 void 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 else2004 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 current2016 * write position.2017 * @param cFrames Number of frames of silence.2018 * @sa AudioMixBufWrite2019 *2020 * @note Does not advance the write position, please call AudioMixBufCommit()2021 * to do that.2022 */2023 void 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_STRICT2036 uint32_t const cMixBufFree = pMixBuf->cFrames - pMixBuf->cUsed;2037 #endif2038 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 a2074 * 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 AudioMixBufSilence2080 */2081 void AudioMixBufBlendGap(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFWRITESTATE pState, uint32_t cFrames)2082 {2083 /*2084 * For now we'll just reset the resampling state regardless of how many2085 * 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 AudioMixBufCommit2100 */2101 void 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 */2116 static 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 */2233 static 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, AudioMixBufSetVolume2277 */2278 void 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 */2301 void 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 else2330 {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 TracChangeset
for help on using the changeset viewer.