Loading media/libeffects/downmix/EffectDownmix.cpp +11 −335 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ #include <log/log.h> #include "EffectDownmix.h" #include <math.h> #include <audio_utils/ChannelMix.h> // Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing //#define DOWNMIX_TEST_CHANNEL_INDEX 0 Loading @@ -35,12 +35,13 @@ typedef enum { } downmix_state_t; /* parameters for each downmixer */ typedef struct { struct downmix_object_t { downmix_state_t state; downmix_type_t type; bool apply_volume_correction; uint8_t input_channel_count; } downmix_object_t; android::audio_utils::channels::ChannelMix channelMix; }; typedef struct downmix_module_s { const struct effect_interface_s *itfe; Loading Loading @@ -77,11 +78,6 @@ static int Downmix_setParameter( downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue); static int Downmix_getParameter( downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue); static void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static bool Downmix_foldGeneric( uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate); // effect_handle_t interface implementation for downmix effect const struct effect_interface_s gDownmixInterface = { Loading Loading @@ -315,7 +311,8 @@ static int32_t Downmix_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) { downmix_object_t *pDownmixer; float *pSrc, *pDst; const float *pSrc; float *pDst; downmix_module_t *pDwmModule = (downmix_module_t *)self; if (pDwmModule == NULL) { Loading Loading @@ -344,7 +341,8 @@ static int32_t Downmix_Process(effect_handle_t self, const bool accumulate = (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels; const audio_channel_mask_t downmixInputChannelMask = (audio_channel_mask_t)pDwmModule->config.inputCfg.channels; switch(pDownmixer->type) { Loading @@ -368,38 +366,13 @@ static int32_t Downmix_Process(effect_handle_t self, } break; case DOWNMIX_TYPE_FOLD: #ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER // bypass the optimized downmix routines for the common formats if (!Downmix_foldGeneric( downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { ALOGE("Multichannel configuration %#x is not supported", downmixInputChannelMask); return -EINVAL; } break; #endif // optimize for the common formats switch (downmixInputChannelMask) { case AUDIO_CHANNEL_OUT_QUAD_BACK: case AUDIO_CHANNEL_OUT_QUAD_SIDE: Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate); break; case AUDIO_CHANNEL_OUT_5POINT1_BACK: case AUDIO_CHANNEL_OUT_5POINT1_SIDE: Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate); break; case AUDIO_CHANNEL_OUT_7POINT1: Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate); break; default: if (!Downmix_foldGeneric( downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { case DOWNMIX_TYPE_FOLD: { if (!pDownmixer->channelMix.process( pSrc, pDst, numFrames, accumulate, downmixInputChannelMask)) { ALOGE("Multichannel configuration %#x is not supported", downmixInputChannelMask); return -EINVAL; } break; } break; Loading Loading @@ -780,7 +753,6 @@ static int Downmix_setParameter( return 0; } /* end Downmix_setParameter */ /*---------------------------------------------------------------------------- * Downmix_getParameter() *---------------------------------------------------------------------------- Loading Loading @@ -829,299 +801,3 @@ static int Downmix_getParameter( return 0; } /* end Downmix_getParameter */ /*---------------------------------------------------------------------------- * Downmix_foldFromQuad() *---------------------------------------------------------------------------- * Purpose: * downmix a quad signal to stereo * * Inputs: * pSrc quad audio samples to downmix * numFrames the number of quad frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is RL // sample at index 3 is RR if (accumulate) { while (numFrames) { // FL + RL pDst[0] = clamp_float(pDst[0] + ((pSrc[0] + pSrc[2]) / 2.0f)); // FR + RR pDst[1] = clamp_float(pDst[1] + ((pSrc[1] + pSrc[3]) / 2.0f)); pSrc += 4; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // FL + RL pDst[0] = clamp_float((pSrc[0] + pSrc[2]) / 2.0f); // FR + RR pDst[1] = clamp_float((pSrc[1] + pSrc[3]) / 2.0f); pSrc += 4; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldFrom5Point1() *---------------------------------------------------------------------------- * Purpose: * downmix a 5.1 signal to stereo * * Inputs: * pSrc 5.1 audio samples to downmix * numFrames the number of 5.1 frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is FC // sample at index 3 is LFE // sample at index 4 is RL // sample at index 5 is RR // code is mostly duplicated between the two values of accumulate to avoid repeating the test // for every sample if (accumulate) { while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[4]; // FR + centerPlusLfeContrib + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[5]; // accumulate in destination pDst[0] = clamp_float(pDst[0] + (lt / 2.0f)); pDst[1] = clamp_float(pDst[1] + (rt / 2.0f)); pSrc += 6; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[4]; // FR + centerPlusLfeContrib + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[5]; // store in destination pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above pSrc += 6; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldFrom7Point1() *---------------------------------------------------------------------------- * Purpose: * downmix a 7.1 signal to stereo * * Inputs: * pSrc 7.1 audio samples to downmix * numFrames the number of 7.1 frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is FC // sample at index 3 is LFE // sample at index 4 is RL // sample at index 5 is RR // sample at index 6 is SL // sample at index 7 is SR // code is mostly duplicated between the two values of accumulate to avoid repeating the test // for every sample if (accumulate) { while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + SL + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4]; // FR + centerPlusLfeContrib + SR + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5]; //accumulate in destination pDst[0] = clamp_float(pDst[0] + (lt / 2.0f)); pDst[1] = clamp_float(pDst[1] + (rt / 2.0f)); pSrc += 8; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + SL + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4]; // FR + centerPlusLfeContrib + SR + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5]; // store in destination pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above pSrc += 8; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldGeneric() *---------------------------------------------------------------------------- * Purpose: * downmix to stereo a multichannel signal of arbitrary channel position mask. * * Inputs: * mask the channel mask of pSrc * pSrc multichannel audio buffer to downmix * numFrames the number of multichannel frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * * Returns: false if multichannel format is not supported * *---------------------------------------------------------------------------- */ bool Downmix_foldGeneric( uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate) { if (!Downmix_validChannelMask(mask)) { return false; } const int numChan = audio_channel_count_from_out_mask(mask); // compute at what index each channel is: samples will be in the following order: // FL FR FC LFE BL BR BC SL SR // // (transfer matrix) // FL FR FC LFE BL BR BC SL SR // 0.5 0.353 0.353 0.5 0.353 0.5 // 0.5 0.353 0.353 0.5 0.353 0.5 // derive the indices for the transfer matrix columns that have non-zero values. int indexFL = -1; int indexFR = -1; int indexFC = -1; int indexLFE = -1; int indexBL = -1; int indexBR = -1; int indexBC = -1; int indexSL = -1; int indexSR = -1; int index = 0; for (unsigned tmp = mask; (tmp & (AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER)) != 0; ++index) { const unsigned lowestBit = tmp & -(signed)tmp; switch (lowestBit) { case AUDIO_CHANNEL_OUT_FRONT_LEFT: indexFL = index; break; case AUDIO_CHANNEL_OUT_FRONT_RIGHT: indexFR = index; break; case AUDIO_CHANNEL_OUT_FRONT_CENTER: indexFC = index; break; case AUDIO_CHANNEL_OUT_LOW_FREQUENCY: indexLFE = index; break; case AUDIO_CHANNEL_OUT_BACK_LEFT: indexBL = index; break; case AUDIO_CHANNEL_OUT_BACK_RIGHT: indexBR = index; break; case AUDIO_CHANNEL_OUT_BACK_CENTER: indexBC = index; break; case AUDIO_CHANNEL_OUT_SIDE_LEFT: indexSL = index; break; case AUDIO_CHANNEL_OUT_SIDE_RIGHT: indexSR = index; break; } tmp ^= lowestBit; } // With good branch prediction, this should run reasonably fast. // Also consider using a transfer matrix form. while (numFrames) { // compute contribution of FC, BC and LFE float centersLfeContrib = 0; if (indexFC >= 0) centersLfeContrib = pSrc[indexFC]; if (indexLFE >= 0) centersLfeContrib += pSrc[indexLFE]; if (indexBC >= 0) centersLfeContrib += pSrc[indexBC]; centersLfeContrib *= MINUS_3_DB_IN_FLOAT; float ch[2]; ch[0] = centersLfeContrib; ch[1] = centersLfeContrib; // mix in left / right channels if (indexFL >= 0) ch[0] += pSrc[indexFL]; if (indexFR >= 0) ch[1] += pSrc[indexFR]; if (indexSL >= 0) ch[0] += pSrc[indexSL]; if (indexSR >= 0) ch[1] += pSrc[indexSR]; // note pair checks enforce this if indexSL != 0 if (indexBL >= 0) ch[0] += pSrc[indexBL]; if (indexBR >= 0) ch[1] += pSrc[indexBR]; // note pair checks enforce this if indexBL != 0 // scale to prevent overflow. ch[0] *= 0.5f; ch[1] *= 0.5f; if (accumulate) { ch[0] += pDst[0]; ch[1] += pDst[1]; } pDst[0] = clamp_float(ch[0]); pDst[1] = clamp_float(ch[1]); pSrc += numChan; pDst += 2; numFrames--; } return true; } media/libeffects/downmix/benchmark/downmix_benchmark.cpp +31 −58 Original line number Diff line number Diff line Loading @@ -35,16 +35,14 @@ static constexpr audio_channel_mask_t kChannelPositionMasks[] = { AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2, AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK, AUDIO_CHANNEL_OUT_QUAD, // AUDIO_CHANNEL_OUT_QUAD_BACK AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND, AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA, AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK, AUDIO_CHANNEL_OUT_5POINT1, // AUDIO_CHANNEL_OUT_5POINT1_BACK AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_OUT_5POINT1POINT2, Loading @@ -62,58 +60,32 @@ static constexpr effect_uuid_t downmix_uuid = { static constexpr size_t kFrameCount = 1000; /* Pixel 3XL downmix_benchmark: #BM_Downmix/0 4723 ns 4708 ns 148694 #BM_Downmix/1 4717 ns 4702 ns 148873 #BM_Downmix/2 4803 ns 4788 ns 145893 #BM_Downmix/3 5056 ns 5041 ns 139110 #BM_Downmix/4 4710 ns 4696 ns 149625 #BM_Downmix/5 1514 ns 1509 ns 463694 #BM_Downmix/6 1513 ns 1509 ns 463451 #BM_Downmix/7 1516 ns 1511 ns 463899 #BM_Downmix/8 4445 ns 4431 ns 157831 #BM_Downmix/9 5081 ns 5065 ns 138412 #BM_Downmix/10 4354 ns 4341 ns 161247 #BM_Downmix/11 4411 ns 4397 ns 158893 #BM_Downmix/12 4434 ns 4420 ns 157992 #BM_Downmix/13 4845 ns 4830 ns 144873 #BM_Downmix/14 4851 ns 4835 ns 144954 #BM_Downmix/15 4884 ns 4870 ns 144233 #BM_Downmix/16 5832 ns 5813 ns 120565 #BM_Downmix/17 5241 ns 5224 ns 133927 #BM_Downmix/18 5044 ns 5028 ns 139131 #BM_Downmix/19 5244 ns 5227 ns 132315 #BM_Downmix/20 5943 ns 5923 ns 117759 #BM_Downmix/21 5990 ns 5971 ns 117263 #BM_Downmix/22 4468 ns 4454 ns 156689 #BM_Downmix/23 7306 ns 7286 ns 95911 -- downmix_benchmark: (generic fold) #BM_Downmix/0 4722 ns 4707 ns 149847 #BM_Downmix/1 4714 ns 4698 ns 148748 #BM_Downmix/2 4794 ns 4779 ns 145661 #BM_Downmix/3 5053 ns 5035 ns 139172 #BM_Downmix/4 4695 ns 4678 ns 149762 #BM_Downmix/5 4381 ns 4368 ns 159675 #BM_Downmix/6 4387 ns 4373 ns 160267 #BM_Downmix/7 4732 ns 4717 ns 148514 #BM_Downmix/8 4430 ns 4415 ns 158133 #BM_Downmix/9 5101 ns 5084 ns 138353 #BM_Downmix/10 4356 ns 4343 ns 160821 #BM_Downmix/11 4397 ns 4383 ns 159995 #BM_Downmix/12 4438 ns 4424 ns 158117 #BM_Downmix/13 5243 ns 5226 ns 133863 #BM_Downmix/14 5259 ns 5242 ns 131855 #BM_Downmix/15 5245 ns 5228 ns 133686 #BM_Downmix/16 5829 ns 5809 ns 120543 #BM_Downmix/17 5245 ns 5228 ns 133533 #BM_Downmix/18 5935 ns 5916 ns 118282 #BM_Downmix/19 5263 ns 5245 ns 133657 #BM_Downmix/20 5998 ns 5978 ns 114693 #BM_Downmix/21 5989 ns 5969 ns 117450 #BM_Downmix/22 4442 ns 4431 ns 157913 #BM_Downmix/23 7309 ns 7290 ns 95797 Pixel 4XL -------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------- BM_Downmix/0 3553 ns 3545 ns 197503 AUDIO_CHANNEL_OUT_MONO BM_Downmix/1 2846 ns 2840 ns 202849 BM_Downmix/2 4436 ns 4426 ns 158176 AUDIO_CHANNEL_OUT_STEREO BM_Downmix/3 5320 ns 5307 ns 131870 AUDIO_CHANNEL_OUT_2POINT1 BM_Downmix/4 4437 ns 4426 ns 159523 AUDIO_CHANNEL_OUT_2POINT0POINT2 BM_Downmix/5 2493 ns 2487 ns 281496 AUDIO_CHANNEL_OUT_QUAD BM_Downmix/6 2493 ns 2487 ns 281456 AUDIO_CHANNEL_OUT_QUAD_SIDE BM_Downmix/7 6204 ns 6188 ns 115044 AUDIO_CHANNEL_OUT_SURROUND BM_Downmix/8 5320 ns 5307 ns 100000 AUDIO_CHANNEL_OUT_2POINT1POINT2 BM_Downmix/9 5320 ns 5307 ns 100000 AUDIO_CHANNEL_OUT_3POINT0POINT2 BM_Downmix/10 7088 ns 7071 ns 108264 AUDIO_CHANNEL_OUT_PENTA BM_Downmix/11 6203 ns 6188 ns 117021 AUDIO_CHANNEL_OUT_3POINT1POINT2 BM_Downmix/12 3105 ns 3097 ns 226182 AUDIO_CHANNEL_OUT_5POINT1 BM_Downmix/13 3112 ns 3105 ns 225488 AUDIO_CHANNEL_OUT_5POINT1_SIDE BM_Downmix/14 8855 ns 8831 ns 79265 AUDIO_CHANNEL_OUT_6POINT1 BM_Downmix/15 7971 ns 7951 ns 90918 AUDIO_CHANNEL_OUT_5POINT1POINT2 BM_Downmix/16 3547 ns 3539 ns 197780 AUDIO_CHANNEL_OUT_7POINT1 BM_Downmix/17 7972 ns 7953 ns 90101 AUDIO_CHANNEL_OUT_5POINT1POINT4 BM_Downmix/18 9737 ns 9714 ns 72773 AUDIO_CHANNEL_OUT_7POINT1POINT2 BM_Downmix/19 9745 ns 9721 ns 72015 AUDIO_CHANNEL_OUT_7POINT1POINT4 BM_Downmix/20 7070 ns 7053 ns 109476 AUDIO_CHANNEL_OUT_13POINT_360RA BM_Downmix/21 12413 ns 12381 ns 57455 AUDIO_CHANNEL_OUT_22POINT2 */ static void BM_Downmix(benchmark::State& state) { Loading @@ -125,7 +97,7 @@ static void BM_Downmix(benchmark::State& state) { std::minstd_rand gen(channelMask); std::uniform_real_distribution<> dis(-1.0f, 1.0f); std::vector<float> input(kFrameCount * channelCount); std::vector<float> output(kFrameCount * 2); std::vector<float> output(kFrameCount * FCC_2); for (auto& in : input) { in = dis(gen); } Loading Loading @@ -187,7 +159,8 @@ static void BM_Downmix(benchmark::State& state) { benchmark::ClobberMemory(); } state.SetComplexityN(state.range(0)); state.SetComplexityN(channelCount); state.SetLabel(audio_channel_out_mask_to_string(channelMask)); if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) { ALOGE("release_effect returned an error = %d\n", status); Loading media/libeffects/downmix/tests/downmix_tests.cpp +49 −22 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libeffects/downmix/EffectDownmix.cpp +11 −335 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ #include <log/log.h> #include "EffectDownmix.h" #include <math.h> #include <audio_utils/ChannelMix.h> // Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing //#define DOWNMIX_TEST_CHANNEL_INDEX 0 Loading @@ -35,12 +35,13 @@ typedef enum { } downmix_state_t; /* parameters for each downmixer */ typedef struct { struct downmix_object_t { downmix_state_t state; downmix_type_t type; bool apply_volume_correction; uint8_t input_channel_count; } downmix_object_t; android::audio_utils::channels::ChannelMix channelMix; }; typedef struct downmix_module_s { const struct effect_interface_s *itfe; Loading Loading @@ -77,11 +78,6 @@ static int Downmix_setParameter( downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue); static int Downmix_getParameter( downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue); static void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate); static bool Downmix_foldGeneric( uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate); // effect_handle_t interface implementation for downmix effect const struct effect_interface_s gDownmixInterface = { Loading Loading @@ -315,7 +311,8 @@ static int32_t Downmix_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) { downmix_object_t *pDownmixer; float *pSrc, *pDst; const float *pSrc; float *pDst; downmix_module_t *pDwmModule = (downmix_module_t *)self; if (pDwmModule == NULL) { Loading Loading @@ -344,7 +341,8 @@ static int32_t Downmix_Process(effect_handle_t self, const bool accumulate = (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels; const audio_channel_mask_t downmixInputChannelMask = (audio_channel_mask_t)pDwmModule->config.inputCfg.channels; switch(pDownmixer->type) { Loading @@ -368,38 +366,13 @@ static int32_t Downmix_Process(effect_handle_t self, } break; case DOWNMIX_TYPE_FOLD: #ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER // bypass the optimized downmix routines for the common formats if (!Downmix_foldGeneric( downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { ALOGE("Multichannel configuration %#x is not supported", downmixInputChannelMask); return -EINVAL; } break; #endif // optimize for the common formats switch (downmixInputChannelMask) { case AUDIO_CHANNEL_OUT_QUAD_BACK: case AUDIO_CHANNEL_OUT_QUAD_SIDE: Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate); break; case AUDIO_CHANNEL_OUT_5POINT1_BACK: case AUDIO_CHANNEL_OUT_5POINT1_SIDE: Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate); break; case AUDIO_CHANNEL_OUT_7POINT1: Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate); break; default: if (!Downmix_foldGeneric( downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { case DOWNMIX_TYPE_FOLD: { if (!pDownmixer->channelMix.process( pSrc, pDst, numFrames, accumulate, downmixInputChannelMask)) { ALOGE("Multichannel configuration %#x is not supported", downmixInputChannelMask); return -EINVAL; } break; } break; Loading Loading @@ -780,7 +753,6 @@ static int Downmix_setParameter( return 0; } /* end Downmix_setParameter */ /*---------------------------------------------------------------------------- * Downmix_getParameter() *---------------------------------------------------------------------------- Loading Loading @@ -829,299 +801,3 @@ static int Downmix_getParameter( return 0; } /* end Downmix_getParameter */ /*---------------------------------------------------------------------------- * Downmix_foldFromQuad() *---------------------------------------------------------------------------- * Purpose: * downmix a quad signal to stereo * * Inputs: * pSrc quad audio samples to downmix * numFrames the number of quad frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFromQuad(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is RL // sample at index 3 is RR if (accumulate) { while (numFrames) { // FL + RL pDst[0] = clamp_float(pDst[0] + ((pSrc[0] + pSrc[2]) / 2.0f)); // FR + RR pDst[1] = clamp_float(pDst[1] + ((pSrc[1] + pSrc[3]) / 2.0f)); pSrc += 4; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // FL + RL pDst[0] = clamp_float((pSrc[0] + pSrc[2]) / 2.0f); // FR + RR pDst[1] = clamp_float((pSrc[1] + pSrc[3]) / 2.0f); pSrc += 4; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldFrom5Point1() *---------------------------------------------------------------------------- * Purpose: * downmix a 5.1 signal to stereo * * Inputs: * pSrc 5.1 audio samples to downmix * numFrames the number of 5.1 frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFrom5Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is FC // sample at index 3 is LFE // sample at index 4 is RL // sample at index 5 is RR // code is mostly duplicated between the two values of accumulate to avoid repeating the test // for every sample if (accumulate) { while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[4]; // FR + centerPlusLfeContrib + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[5]; // accumulate in destination pDst[0] = clamp_float(pDst[0] + (lt / 2.0f)); pDst[1] = clamp_float(pDst[1] + (rt / 2.0f)); pSrc += 6; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[4]; // FR + centerPlusLfeContrib + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[5]; // store in destination pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above pSrc += 6; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldFrom7Point1() *---------------------------------------------------------------------------- * Purpose: * downmix a 7.1 signal to stereo * * Inputs: * pSrc 7.1 audio samples to downmix * numFrames the number of 7.1 frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * *---------------------------------------------------------------------------- */ void Downmix_foldFrom7Point1(float *pSrc, float *pDst, size_t numFrames, bool accumulate) { float lt, rt, centerPlusLfeContrib; // samples in Q19.12 format // sample at index 0 is FL // sample at index 1 is FR // sample at index 2 is FC // sample at index 3 is LFE // sample at index 4 is RL // sample at index 5 is RR // sample at index 6 is SL // sample at index 7 is SR // code is mostly duplicated between the two values of accumulate to avoid repeating the test // for every sample if (accumulate) { while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + SL + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4]; // FR + centerPlusLfeContrib + SR + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5]; //accumulate in destination pDst[0] = clamp_float(pDst[0] + (lt / 2.0f)); pDst[1] = clamp_float(pDst[1] + (rt / 2.0f)); pSrc += 8; pDst += 2; numFrames--; } } else { // same code as above but without adding and clamping pDst[i] to itself while (numFrames) { // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_FLOAT) + (pSrc[3] * MINUS_3_DB_IN_FLOAT); // FL + centerPlusLfeContrib + SL + RL lt = pSrc[0] + centerPlusLfeContrib + pSrc[6] + pSrc[4]; // FR + centerPlusLfeContrib + SR + RR rt = pSrc[1] + centerPlusLfeContrib + pSrc[7] + pSrc[5]; // store in destination pDst[0] = clamp_float(lt / 2.0f); // differs from when accumulate is true above pDst[1] = clamp_float(rt / 2.0f); // differs from when accumulate is true above pSrc += 8; pDst += 2; numFrames--; } } } /*---------------------------------------------------------------------------- * Downmix_foldGeneric() *---------------------------------------------------------------------------- * Purpose: * downmix to stereo a multichannel signal of arbitrary channel position mask. * * Inputs: * mask the channel mask of pSrc * pSrc multichannel audio buffer to downmix * numFrames the number of multichannel frames to downmix * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, * or overwrite pDst (when false) * * Outputs: * pDst downmixed stereo audio samples * * Returns: false if multichannel format is not supported * *---------------------------------------------------------------------------- */ bool Downmix_foldGeneric( uint32_t mask, float *pSrc, float *pDst, size_t numFrames, bool accumulate) { if (!Downmix_validChannelMask(mask)) { return false; } const int numChan = audio_channel_count_from_out_mask(mask); // compute at what index each channel is: samples will be in the following order: // FL FR FC LFE BL BR BC SL SR // // (transfer matrix) // FL FR FC LFE BL BR BC SL SR // 0.5 0.353 0.353 0.5 0.353 0.5 // 0.5 0.353 0.353 0.5 0.353 0.5 // derive the indices for the transfer matrix columns that have non-zero values. int indexFL = -1; int indexFR = -1; int indexFC = -1; int indexLFE = -1; int indexBL = -1; int indexBR = -1; int indexBC = -1; int indexSL = -1; int indexSR = -1; int index = 0; for (unsigned tmp = mask; (tmp & (AUDIO_CHANNEL_OUT_7POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER)) != 0; ++index) { const unsigned lowestBit = tmp & -(signed)tmp; switch (lowestBit) { case AUDIO_CHANNEL_OUT_FRONT_LEFT: indexFL = index; break; case AUDIO_CHANNEL_OUT_FRONT_RIGHT: indexFR = index; break; case AUDIO_CHANNEL_OUT_FRONT_CENTER: indexFC = index; break; case AUDIO_CHANNEL_OUT_LOW_FREQUENCY: indexLFE = index; break; case AUDIO_CHANNEL_OUT_BACK_LEFT: indexBL = index; break; case AUDIO_CHANNEL_OUT_BACK_RIGHT: indexBR = index; break; case AUDIO_CHANNEL_OUT_BACK_CENTER: indexBC = index; break; case AUDIO_CHANNEL_OUT_SIDE_LEFT: indexSL = index; break; case AUDIO_CHANNEL_OUT_SIDE_RIGHT: indexSR = index; break; } tmp ^= lowestBit; } // With good branch prediction, this should run reasonably fast. // Also consider using a transfer matrix form. while (numFrames) { // compute contribution of FC, BC and LFE float centersLfeContrib = 0; if (indexFC >= 0) centersLfeContrib = pSrc[indexFC]; if (indexLFE >= 0) centersLfeContrib += pSrc[indexLFE]; if (indexBC >= 0) centersLfeContrib += pSrc[indexBC]; centersLfeContrib *= MINUS_3_DB_IN_FLOAT; float ch[2]; ch[0] = centersLfeContrib; ch[1] = centersLfeContrib; // mix in left / right channels if (indexFL >= 0) ch[0] += pSrc[indexFL]; if (indexFR >= 0) ch[1] += pSrc[indexFR]; if (indexSL >= 0) ch[0] += pSrc[indexSL]; if (indexSR >= 0) ch[1] += pSrc[indexSR]; // note pair checks enforce this if indexSL != 0 if (indexBL >= 0) ch[0] += pSrc[indexBL]; if (indexBR >= 0) ch[1] += pSrc[indexBR]; // note pair checks enforce this if indexBL != 0 // scale to prevent overflow. ch[0] *= 0.5f; ch[1] *= 0.5f; if (accumulate) { ch[0] += pDst[0]; ch[1] += pDst[1]; } pDst[0] = clamp_float(ch[0]); pDst[1] = clamp_float(ch[1]); pSrc += numChan; pDst += 2; numFrames--; } return true; }
media/libeffects/downmix/benchmark/downmix_benchmark.cpp +31 −58 Original line number Diff line number Diff line Loading @@ -35,16 +35,14 @@ static constexpr audio_channel_mask_t kChannelPositionMasks[] = { AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2, AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK, AUDIO_CHANNEL_OUT_QUAD, // AUDIO_CHANNEL_OUT_QUAD_BACK AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND, AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA, AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK, AUDIO_CHANNEL_OUT_5POINT1, // AUDIO_CHANNEL_OUT_5POINT1_BACK AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_OUT_5POINT1POINT2, Loading @@ -62,58 +60,32 @@ static constexpr effect_uuid_t downmix_uuid = { static constexpr size_t kFrameCount = 1000; /* Pixel 3XL downmix_benchmark: #BM_Downmix/0 4723 ns 4708 ns 148694 #BM_Downmix/1 4717 ns 4702 ns 148873 #BM_Downmix/2 4803 ns 4788 ns 145893 #BM_Downmix/3 5056 ns 5041 ns 139110 #BM_Downmix/4 4710 ns 4696 ns 149625 #BM_Downmix/5 1514 ns 1509 ns 463694 #BM_Downmix/6 1513 ns 1509 ns 463451 #BM_Downmix/7 1516 ns 1511 ns 463899 #BM_Downmix/8 4445 ns 4431 ns 157831 #BM_Downmix/9 5081 ns 5065 ns 138412 #BM_Downmix/10 4354 ns 4341 ns 161247 #BM_Downmix/11 4411 ns 4397 ns 158893 #BM_Downmix/12 4434 ns 4420 ns 157992 #BM_Downmix/13 4845 ns 4830 ns 144873 #BM_Downmix/14 4851 ns 4835 ns 144954 #BM_Downmix/15 4884 ns 4870 ns 144233 #BM_Downmix/16 5832 ns 5813 ns 120565 #BM_Downmix/17 5241 ns 5224 ns 133927 #BM_Downmix/18 5044 ns 5028 ns 139131 #BM_Downmix/19 5244 ns 5227 ns 132315 #BM_Downmix/20 5943 ns 5923 ns 117759 #BM_Downmix/21 5990 ns 5971 ns 117263 #BM_Downmix/22 4468 ns 4454 ns 156689 #BM_Downmix/23 7306 ns 7286 ns 95911 -- downmix_benchmark: (generic fold) #BM_Downmix/0 4722 ns 4707 ns 149847 #BM_Downmix/1 4714 ns 4698 ns 148748 #BM_Downmix/2 4794 ns 4779 ns 145661 #BM_Downmix/3 5053 ns 5035 ns 139172 #BM_Downmix/4 4695 ns 4678 ns 149762 #BM_Downmix/5 4381 ns 4368 ns 159675 #BM_Downmix/6 4387 ns 4373 ns 160267 #BM_Downmix/7 4732 ns 4717 ns 148514 #BM_Downmix/8 4430 ns 4415 ns 158133 #BM_Downmix/9 5101 ns 5084 ns 138353 #BM_Downmix/10 4356 ns 4343 ns 160821 #BM_Downmix/11 4397 ns 4383 ns 159995 #BM_Downmix/12 4438 ns 4424 ns 158117 #BM_Downmix/13 5243 ns 5226 ns 133863 #BM_Downmix/14 5259 ns 5242 ns 131855 #BM_Downmix/15 5245 ns 5228 ns 133686 #BM_Downmix/16 5829 ns 5809 ns 120543 #BM_Downmix/17 5245 ns 5228 ns 133533 #BM_Downmix/18 5935 ns 5916 ns 118282 #BM_Downmix/19 5263 ns 5245 ns 133657 #BM_Downmix/20 5998 ns 5978 ns 114693 #BM_Downmix/21 5989 ns 5969 ns 117450 #BM_Downmix/22 4442 ns 4431 ns 157913 #BM_Downmix/23 7309 ns 7290 ns 95797 Pixel 4XL -------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------- BM_Downmix/0 3553 ns 3545 ns 197503 AUDIO_CHANNEL_OUT_MONO BM_Downmix/1 2846 ns 2840 ns 202849 BM_Downmix/2 4436 ns 4426 ns 158176 AUDIO_CHANNEL_OUT_STEREO BM_Downmix/3 5320 ns 5307 ns 131870 AUDIO_CHANNEL_OUT_2POINT1 BM_Downmix/4 4437 ns 4426 ns 159523 AUDIO_CHANNEL_OUT_2POINT0POINT2 BM_Downmix/5 2493 ns 2487 ns 281496 AUDIO_CHANNEL_OUT_QUAD BM_Downmix/6 2493 ns 2487 ns 281456 AUDIO_CHANNEL_OUT_QUAD_SIDE BM_Downmix/7 6204 ns 6188 ns 115044 AUDIO_CHANNEL_OUT_SURROUND BM_Downmix/8 5320 ns 5307 ns 100000 AUDIO_CHANNEL_OUT_2POINT1POINT2 BM_Downmix/9 5320 ns 5307 ns 100000 AUDIO_CHANNEL_OUT_3POINT0POINT2 BM_Downmix/10 7088 ns 7071 ns 108264 AUDIO_CHANNEL_OUT_PENTA BM_Downmix/11 6203 ns 6188 ns 117021 AUDIO_CHANNEL_OUT_3POINT1POINT2 BM_Downmix/12 3105 ns 3097 ns 226182 AUDIO_CHANNEL_OUT_5POINT1 BM_Downmix/13 3112 ns 3105 ns 225488 AUDIO_CHANNEL_OUT_5POINT1_SIDE BM_Downmix/14 8855 ns 8831 ns 79265 AUDIO_CHANNEL_OUT_6POINT1 BM_Downmix/15 7971 ns 7951 ns 90918 AUDIO_CHANNEL_OUT_5POINT1POINT2 BM_Downmix/16 3547 ns 3539 ns 197780 AUDIO_CHANNEL_OUT_7POINT1 BM_Downmix/17 7972 ns 7953 ns 90101 AUDIO_CHANNEL_OUT_5POINT1POINT4 BM_Downmix/18 9737 ns 9714 ns 72773 AUDIO_CHANNEL_OUT_7POINT1POINT2 BM_Downmix/19 9745 ns 9721 ns 72015 AUDIO_CHANNEL_OUT_7POINT1POINT4 BM_Downmix/20 7070 ns 7053 ns 109476 AUDIO_CHANNEL_OUT_13POINT_360RA BM_Downmix/21 12413 ns 12381 ns 57455 AUDIO_CHANNEL_OUT_22POINT2 */ static void BM_Downmix(benchmark::State& state) { Loading @@ -125,7 +97,7 @@ static void BM_Downmix(benchmark::State& state) { std::minstd_rand gen(channelMask); std::uniform_real_distribution<> dis(-1.0f, 1.0f); std::vector<float> input(kFrameCount * channelCount); std::vector<float> output(kFrameCount * 2); std::vector<float> output(kFrameCount * FCC_2); for (auto& in : input) { in = dis(gen); } Loading Loading @@ -187,7 +159,8 @@ static void BM_Downmix(benchmark::State& state) { benchmark::ClobberMemory(); } state.SetComplexityN(state.range(0)); state.SetComplexityN(channelCount); state.SetLabel(audio_channel_out_mask_to_string(channelMask)); if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) { ALOGE("release_effect returned an error = %d\n", status); Loading
media/libeffects/downmix/tests/downmix_tests.cpp +49 −22 File changed.Preview size limit exceeded, changes collapsed. Show changes