Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 559e32f0 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "LoudnessEnhancer: Remove legacy int support" into main

parents 431668ba 629c8bcd
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ license {
    ],
}

cc_library_shared {
cc_library {
    name: "libldnhncr",

    vendor: true,
@@ -36,6 +36,7 @@ cc_library_shared {
    ],

    shared_libs: [
        "libaudioutils",
        "libcutils",
        "liblog",
    ],
@@ -64,6 +65,7 @@ cc_library_shared {
        "-Wthread-safety",
    ],
    shared_libs: [
        "libaudioutils",
        "libcutils",
        "liblog",
    ],
+0 −40
Original line number Diff line number Diff line
@@ -30,26 +30,8 @@
#include <audio_effects/effect_loudnessenhancer.h>
#include "dsp/core/dynamic_range_compression.h"

// BUILD_FLOAT targets building a float effect instead of the legacy int16_t effect.
#define BUILD_FLOAT

#ifdef BUILD_FLOAT

static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;

#else

static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;

static inline int16_t clamp16(int32_t sample)
{
    if ((sample>>15) ^ (sample>>31))
        sample = 0x7FFF ^ (sample>>31);
    return sample;
}

#endif // BUILD_FLOAT

extern "C" {

// effect_handle_t interface implementation for LE effect
@@ -297,33 +279,20 @@ int LE_process(

    //ALOGV("LE about to process %d samples", inBuffer->frameCount);
    uint16_t inIdx;
#ifdef BUILD_FLOAT
    constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
    constexpr float inverseScale = 1.f / scale;
    const float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f) * scale;
#else
    float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
#endif
    float leftSample, rightSample;
    for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
        // makeup gain is applied on the input of the compressor
#ifdef BUILD_FLOAT
        leftSample  = inputAmp * inBuffer->f32[2*inIdx];
        rightSample = inputAmp * inBuffer->f32[2*inIdx +1];
        pContext->mCompressor->Compress(&leftSample, &rightSample);
        inBuffer->f32[2*inIdx]    = leftSample * inverseScale;
        inBuffer->f32[2*inIdx +1] = rightSample * inverseScale;
#else
        leftSample  = inputAmp * (float)inBuffer->s16[2*inIdx];
        rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
        pContext->mCompressor->Compress(&leftSample, &rightSample);
        inBuffer->s16[2*inIdx]    = (int16_t) leftSample;
        inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
#endif // BUILD_FLOAT
    }

    if (inBuffer->raw != outBuffer->raw) {
#ifdef BUILD_FLOAT
        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
                outBuffer->f32[i] += inBuffer->f32[i];
@@ -331,15 +300,6 @@ int LE_process(
        } else {
            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(float));
        }
#else
        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
            }
        } else {
            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
        }
#endif // BUILD_FLOAT
    }
    if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
        return -ENODATA;
+36 −0
Original line number Diff line number Diff line
// Build the unit tests for loudness effect tests

package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "frameworks_av_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["frameworks_av_license"],
}

cc_test {
    name: "loudness_enhancer_tests",
    srcs: [
        "loudness_enhancer_tests.cpp",
    ],
    shared_libs: [
        "libbase",
        "liblog",
    ],
    static_libs: [
        "libldnhncr",
    ],
    header_libs: [
        "libaudioeffects",
        "libaudioutils_headers",
    ],
    include_dirs: [
        "frameworks/av/media/libeffects/loudness",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wthread-safety",
    ],
}
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dsp/core/dynamic_range_compression.h"
#include <audio_effects/effect_loudnessenhancer.h>
#include <audio_utils/dsp_utils.h>
#include <system/audio_effects/audio_effects_test.h>
#include <gtest/gtest.h>

using status_t = int32_t;
extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
effect_uuid_t loudness_uuid = {0xfa415329, 0x2034, 0x4bea, 0xb5dc,
    {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}};

using namespace android::audio_utils;
using namespace android::effect::utils;

// Android 16:
// expectedEnergydB: -24.771212  energyIndB: -24.739433
// gaindB: 0.000000  measureddB: 0.000000  energyIndB: -24.739433  energyOutdB: -24.739433
// gaindB: 1.000000  measureddB: 1.000004  energyIndB: -24.739433  energyOutdB: -23.739429
// gaindB: 2.000000  measureddB: 2.000002  energyIndB: -24.739433  energyOutdB: -22.739431
// gaindB: 5.000000  measureddB: 5.000006  energyIndB: -24.739433  energyOutdB: -19.739428
// gaindB: 10.000000  measureddB: 10.000004  energyIndB: -24.739433  energyOutdB: -14.739429
// -- gain saturates below as the output approaches 0dBov.
// gaindB: 20.000000  measureddB: 13.444631  energyIndB: -24.739433  energyOutdB: -11.294803
// gaindB: 50.000000  measureddB: 18.691999  energyIndB: -24.739433  energyOutdB: -6.047434
// gaindB: 100.000000  measureddB: 22.908695  energyIndB: -24.739433  energyOutdB: -1.830737

TEST(loudness_enhancer, gain_check) {
    effect_handle_t handle;
    ASSERT_EQ(0, AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
            &loudness_uuid, 0 /* sessionId */, 0 /* ioId */, &handle));

    ASSERT_EQ(0, effect_enable(handle));

    constexpr size_t frameCount = 1024;
    constexpr size_t channelCount = 2;
    constexpr float amplitude = 0.1;
    const size_t sampleCount = channelCount * frameCount;
    std::vector<float> originalData(sampleCount);
    initUniformDistribution(originalData, -amplitude, amplitude);
    std::vector<float> outData(sampleCount);

    // compute the expected energy in dB for a uniform distribution from -amplitude to amplitude.
    const float expectedEnergydB = energyOfUniformDistribution(-amplitude, amplitude);
    const float energyIndB = energy(originalData);
    ALOGD("%s: expectedEnergydB: %f  energyIndB: %f", __func__, expectedEnergydB, energyIndB);
    EXPECT_NEAR(energyIndB, expectedEnergydB, 0.1);  // within 0.1dB.
    float lastMeasuredGaindB = 0;
    for (int gainmB : { 0, 100, 200, 500, 1'000, 2'000, 5'000, 10'000 }) {  // millibel Power
        ASSERT_EQ(0, effect_set_param(handle, LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, gainmB));

        auto inData = originalData;
        audio_buffer_t inBuffer{ .frameCount = frameCount, .f32 = inData.data() };
        audio_buffer_t outBuffer{ .frameCount = frameCount, .f32 = outData.data() };
        ASSERT_EQ(0, effect_process(handle, &inBuffer, &outBuffer));
        const float energyOutdB = energy(inData);
        const float gaindB = gainmB * 1e-2;
        const float measuredGaindB = energyOutdB - energyIndB;

        // Log our gain and power levels
        ALOGD("%s: gaindB: %f  measureddB: %f  energyIndB: %f  energyOutdB: %f",
                __func__, gaindB, measuredGaindB, energyIndB, energyOutdB);

        // Gain curve testing (move to VTS)?
        if (gaindB == 0) {
            EXPECT_EQ(energyIndB, energyOutdB);
        } else if (energyIndB + gaindB < -10.f) {
            // less than -10dB from overflow, signal does not saturate.
            EXPECT_NEAR(gaindB, measuredGaindB, 0.1);
        } else {  // effective gain saturates.
            EXPECT_LT(measuredGaindB, gaindB);       // we're less than the desired gain.
            EXPECT_GT(measuredGaindB, lastMeasuredGaindB);  // we're more than the previous gain.
        }
        lastMeasuredGaindB = measuredGaindB;
    }
    ASSERT_EQ(0, AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(handle));
}