Loading media/libeffects/loudness/Android.bp +29 −0 Original line number Diff line number Diff line Loading @@ -44,3 +44,32 @@ cc_library_shared { header_libs: ["libaudioeffects"], } cc_library_shared { name: "libloudnessenhanceraidl", srcs: [ "aidl/EffectLoudnessEnhancer.cpp", "aidl/LoudnessEnhancerContext.cpp", "dsp/core/dynamic_range_compression.cpp", ":effectCommonFile", ], defaults: [ "aidlaudioservice_defaults", "latest_android_hardware_audio_effect_ndk_shared", "latest_android_media_audio_common_types_ndk_shared", ], header_libs: [ "libaudioeffects", "libhardware_headers", ], cflags: [ "-Wthread-safety", ], shared_libs: [ "libcutils", "liblog", ], visibility: [ "//hardware/interfaces/audio/aidl/default", ], } media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp 0 → 100644 +182 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #define LOG_TAG "AHAL_LoudnessEnhancerImpl" #include <android-base/logging.h> #include "EffectLoudnessEnhancer.h" using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::kLoudnessEnhancerImplUUID; using aidl::android::hardware::audio::effect::LoudnessEnhancerImpl; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr<IEffect>* instanceSpp) { if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } if (instanceSpp) { *instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerImpl>(); LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created"; return EX_NONE; } else { LOG(ERROR) << __func__ << " invalid input parameter!"; return EX_ILLEGAL_ARGUMENT; } } extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) { if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } *_aidl_return = LoudnessEnhancerImpl::kDescriptor; return EX_NONE; } namespace aidl::android::hardware::audio::effect { const std::string LoudnessEnhancerImpl::kEffectName = "Loudness Enhancer"; const Descriptor LoudnessEnhancerImpl::kDescriptor = { .common = {.id = {.type = kLoudnessEnhancerTypeUUID, .uuid = kLoudnessEnhancerImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST}, .name = LoudnessEnhancerImpl::kEffectName, .implementor = "The Android Open Source Project"}}; ndk::ScopedAStatus LoudnessEnhancerImpl::getDescriptor(Descriptor* _aidl_return) { RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr"); LOG(DEBUG) << __func__ << kDescriptor.toString(); *_aidl_return = kDescriptor; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus LoudnessEnhancerImpl::commandImpl(CommandId command) { RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); switch (command) { case CommandId::START: mContext->enable(); break; case CommandId::STOP: mContext->disable(); break; case CommandId::RESET: mContext->disable(); mContext->resetBuffer(); break; default: LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported"; return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "commandIdNotSupported"); } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus LoudnessEnhancerImpl::setParameterSpecific(const Parameter::Specific& specific) { RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>(); auto tag = leParam.getTag(); switch (tag) { case LoudnessEnhancer::gainMb: { RETURN_IF(mContext->setLeGain(leParam.get<LoudnessEnhancer::gainMb>()) != RetCode::SUCCESS, EX_ILLEGAL_ARGUMENT, "setGainMbFailed"); return ndk::ScopedAStatus::ok(); } default: { LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } } ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) { RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr"); auto tag = id.getTag(); RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); auto leId = id.get<Parameter::Id::loudnessEnhancerTag>(); auto leIdTag = leId.getTag(); switch (leIdTag) { case LoudnessEnhancer::Id::commonTag: return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(), specific); default: LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterLoudnessEnhancer( const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) { RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); LoudnessEnhancer leParam; switch (tag) { case LoudnessEnhancer::gainMb: { leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGain()); break; } default: { LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } specific->set<Parameter::Specific::loudnessEnhancer>(leParam); return ndk::ScopedAStatus::ok(); } std::shared_ptr<EffectContext> LoudnessEnhancerImpl::createContext( const Parameter::Common& common) { if (mContext) { LOG(DEBUG) << __func__ << " context already exist"; return mContext; } mContext = std::make_shared<LoudnessEnhancerContext>(1 /* statusFmqDepth */, common); return mContext; } RetCode LoudnessEnhancerImpl::releaseContext() { if (mContext) { mContext->disable(); mContext->resetBuffer(); } return RetCode::SUCCESS; } // Processing method running in EffectWorker thread. IEffect::Status LoudnessEnhancerImpl::effectProcessImpl(float* in, float* out, int samples) { IEffect::Status status = {EX_NULL_POINTER, 0, 0}; RETURN_VALUE_IF(!mContext, status, "nullContext"); return mContext->lvmProcess(in, out, samples); } } // namespace aidl::android::hardware::audio::effect media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <aidl/android/hardware/audio/effect/BnEffect.h> #include "effect-impl/EffectImpl.h" #include "effect-impl/EffectUUID.h" #include "LoudnessEnhancerContext.h" namespace aidl::android::hardware::audio::effect { class LoudnessEnhancerImpl final : public EffectImpl { public: static const std::string kEffectName; static const Descriptor kDescriptor; LoudnessEnhancerImpl() { LOG(DEBUG) << __func__; } ~LoudnessEnhancerImpl() { cleanUp(); LOG(DEBUG) << __func__; } ndk::ScopedAStatus commandImpl(CommandId command) override; ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override; ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) override; IEffect::Status effectProcessImpl(float* in, float* out, int process) override; std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override; RetCode releaseContext() override; std::shared_ptr<EffectContext> getContext() override { return mContext; } std::string getEffectName() override { return kEffectName; } private: std::shared_ptr<LoudnessEnhancerContext> mContext; ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific); }; } // namespace aidl::android::hardware::audio::effect media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp 0 → 100644 +130 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "LoudnessEnhancerContext.h" namespace aidl::android::hardware::audio::effect { LoudnessEnhancerContext::LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common) : EffectContext(statusDepth, common) { LOG(DEBUG) << __func__; mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; mSampleRate = common.input.base.sampleRate; init_params(); } LoudnessEnhancerContext::~LoudnessEnhancerContext() { LOG(DEBUG) << __func__; mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; } RetCode LoudnessEnhancerContext::enable() { if (mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) { return RetCode::ERROR_EFFECT_LIB_ERROR; } mState = LOUDNESS_ENHANCER_STATE_ACTIVE; return RetCode::SUCCESS; } RetCode LoudnessEnhancerContext::disable() { if (mState != LOUDNESS_ENHANCER_STATE_ACTIVE) { return RetCode::ERROR_EFFECT_LIB_ERROR; } mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; return RetCode::SUCCESS; } void LoudnessEnhancerContext::reset() { float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification { std::lock_guard lg(mMutex); if (mCompressor != nullptr) { // Get samplingRate from input mCompressor->Initialize(targetAmp, mSampleRate); } } } RetCode LoudnessEnhancerContext::setLeGain(int gainMb) { mGain = gainMb; reset(); // apply parameter update return RetCode::SUCCESS; } IEffect::Status LoudnessEnhancerContext::lvmProcess(float* in, float* out, int samples) { LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples; IEffect::Status status = {EX_NULL_POINTER, 0, 0}; RETURN_VALUE_IF(!in, status, "nullInput"); RETURN_VALUE_IF(!out, status, "nullOutput"); status = {EX_ILLEGAL_STATE, 0, 0}; RETURN_VALUE_IF(getInputFrameSize() != getOutputFrameSize(), status, "FrameSizeMismatch"); auto frameSize = getInputFrameSize(); RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize"); LOG(DEBUG) << __func__ << " start processing"; { std::lock_guard lg(mMutex); // PcmType is always expected to be Float 32 bit. 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, mGain / 2000.0f) * scale; float leftSample, rightSample; if (mCompressor != nullptr) { for (int inIdx = 0; inIdx < samples; inIdx += 2) { // makeup gain is applied on the input of the compressor leftSample = inputAmp * in[inIdx]; rightSample = inputAmp * in[inIdx + 1]; mCompressor->Compress(&leftSample, &rightSample); in[inIdx] = leftSample * inverseScale; in[inIdx + 1] = rightSample * inverseScale; } } else { for (int inIdx = 0; inIdx < samples; inIdx += 2) { leftSample = inputAmp * in[inIdx]; rightSample = inputAmp * in[inIdx + 1]; in[inIdx] = leftSample * inverseScale; in[inIdx + 1] = rightSample * inverseScale; } } bool accumulate = false; if (in != out) { for (int i = 0; i < samples; i++) { if (accumulate) { out[i] += in[i]; } else { out[i] = in[i]; } } } } return {STATUS_OK, samples, samples}; } void LoudnessEnhancerContext::init_params() { mGain = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB; float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification LOG(DEBUG) << __func__ << "Target gain = " << mGain << "mB <=> factor = " << targetAmp; { std::lock_guard lg(mMutex); mCompressor = std::make_unique<le_fx::AdaptiveDynamicRangeCompression>(); mCompressor->Initialize(targetAmp, mSampleRate); } mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; } } // namespace aidl::android::hardware::audio::effect media/libeffects/loudness/aidl/LoudnessEnhancerContext.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <android-base/thread_annotations.h> #include <audio_effects/effect_loudnessenhancer.h> #include "dsp/core/dynamic_range_compression.h" #include "effect-impl/EffectContext.h" namespace aidl::android::hardware::audio::effect { enum LoudnessEnhancerState { LOUDNESS_ENHANCER_STATE_UNINITIALIZED, LOUDNESS_ENHANCER_STATE_INITIALIZED, LOUDNESS_ENHANCER_STATE_ACTIVE, }; class LoudnessEnhancerContext final : public EffectContext { public: LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common); ~LoudnessEnhancerContext(); RetCode enable(); RetCode disable(); void reset(); RetCode setLeGain(int gainMb); int getLeGain() const { return mGain; } IEffect::Status lvmProcess(float* in, float* out, int samples); private: std::mutex mMutex; LoudnessEnhancerState mState; int mSampleRate; int mGain; // In this implementation, there is no coupling between the compression on the left and right // channels std::unique_ptr<le_fx::AdaptiveDynamicRangeCompression> mCompressor GUARDED_BY(mMutex); void init_params(); }; } // namespace aidl::android::hardware::audio::effect Loading
media/libeffects/loudness/Android.bp +29 −0 Original line number Diff line number Diff line Loading @@ -44,3 +44,32 @@ cc_library_shared { header_libs: ["libaudioeffects"], } cc_library_shared { name: "libloudnessenhanceraidl", srcs: [ "aidl/EffectLoudnessEnhancer.cpp", "aidl/LoudnessEnhancerContext.cpp", "dsp/core/dynamic_range_compression.cpp", ":effectCommonFile", ], defaults: [ "aidlaudioservice_defaults", "latest_android_hardware_audio_effect_ndk_shared", "latest_android_media_audio_common_types_ndk_shared", ], header_libs: [ "libaudioeffects", "libhardware_headers", ], cflags: [ "-Wthread-safety", ], shared_libs: [ "libcutils", "liblog", ], visibility: [ "//hardware/interfaces/audio/aidl/default", ], }
media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp 0 → 100644 +182 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #define LOG_TAG "AHAL_LoudnessEnhancerImpl" #include <android-base/logging.h> #include "EffectLoudnessEnhancer.h" using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::kLoudnessEnhancerImplUUID; using aidl::android::hardware::audio::effect::LoudnessEnhancerImpl; using aidl::android::hardware::audio::effect::State; using aidl::android::media::audio::common::AudioUuid; extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid, std::shared_ptr<IEffect>* instanceSpp) { if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } if (instanceSpp) { *instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerImpl>(); LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created"; return EX_NONE; } else { LOG(ERROR) << __func__ << " invalid input parameter!"; return EX_ILLEGAL_ARGUMENT; } } extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) { if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerImplUUID) { LOG(ERROR) << __func__ << "uuid not supported"; return EX_ILLEGAL_ARGUMENT; } *_aidl_return = LoudnessEnhancerImpl::kDescriptor; return EX_NONE; } namespace aidl::android::hardware::audio::effect { const std::string LoudnessEnhancerImpl::kEffectName = "Loudness Enhancer"; const Descriptor LoudnessEnhancerImpl::kDescriptor = { .common = {.id = {.type = kLoudnessEnhancerTypeUUID, .uuid = kLoudnessEnhancerImplUUID, .proxy = std::nullopt}, .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST}, .name = LoudnessEnhancerImpl::kEffectName, .implementor = "The Android Open Source Project"}}; ndk::ScopedAStatus LoudnessEnhancerImpl::getDescriptor(Descriptor* _aidl_return) { RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr"); LOG(DEBUG) << __func__ << kDescriptor.toString(); *_aidl_return = kDescriptor; return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus LoudnessEnhancerImpl::commandImpl(CommandId command) { RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); switch (command) { case CommandId::START: mContext->enable(); break; case CommandId::STOP: mContext->disable(); break; case CommandId::RESET: mContext->disable(); mContext->resetBuffer(); break; default: LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported"; return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "commandIdNotSupported"); } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus LoudnessEnhancerImpl::setParameterSpecific(const Parameter::Specific& specific) { RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>(); auto tag = leParam.getTag(); switch (tag) { case LoudnessEnhancer::gainMb: { RETURN_IF(mContext->setLeGain(leParam.get<LoudnessEnhancer::gainMb>()) != RetCode::SUCCESS, EX_ILLEGAL_ARGUMENT, "setGainMbFailed"); return ndk::ScopedAStatus::ok(); } default: { LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } } ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) { RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr"); auto tag = id.getTag(); RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); auto leId = id.get<Parameter::Id::loudnessEnhancerTag>(); auto leIdTag = leId.getTag(); switch (leIdTag) { case LoudnessEnhancer::Id::commonTag: return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(), specific); default: LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterLoudnessEnhancer( const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) { RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); LoudnessEnhancer leParam; switch (tag) { case LoudnessEnhancer::gainMb: { leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGain()); break; } default: { LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); return ndk::ScopedAStatus::fromExceptionCodeWithMessage( EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported"); } } specific->set<Parameter::Specific::loudnessEnhancer>(leParam); return ndk::ScopedAStatus::ok(); } std::shared_ptr<EffectContext> LoudnessEnhancerImpl::createContext( const Parameter::Common& common) { if (mContext) { LOG(DEBUG) << __func__ << " context already exist"; return mContext; } mContext = std::make_shared<LoudnessEnhancerContext>(1 /* statusFmqDepth */, common); return mContext; } RetCode LoudnessEnhancerImpl::releaseContext() { if (mContext) { mContext->disable(); mContext->resetBuffer(); } return RetCode::SUCCESS; } // Processing method running in EffectWorker thread. IEffect::Status LoudnessEnhancerImpl::effectProcessImpl(float* in, float* out, int samples) { IEffect::Status status = {EX_NULL_POINTER, 0, 0}; RETURN_VALUE_IF(!mContext, status, "nullContext"); return mContext->lvmProcess(in, out, samples); } } // namespace aidl::android::hardware::audio::effect
media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <aidl/android/hardware/audio/effect/BnEffect.h> #include "effect-impl/EffectImpl.h" #include "effect-impl/EffectUUID.h" #include "LoudnessEnhancerContext.h" namespace aidl::android::hardware::audio::effect { class LoudnessEnhancerImpl final : public EffectImpl { public: static const std::string kEffectName; static const Descriptor kDescriptor; LoudnessEnhancerImpl() { LOG(DEBUG) << __func__; } ~LoudnessEnhancerImpl() { cleanUp(); LOG(DEBUG) << __func__; } ndk::ScopedAStatus commandImpl(CommandId command) override; ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override; ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override; ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) override; IEffect::Status effectProcessImpl(float* in, float* out, int process) override; std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override; RetCode releaseContext() override; std::shared_ptr<EffectContext> getContext() override { return mContext; } std::string getEffectName() override { return kEffectName; } private: std::shared_ptr<LoudnessEnhancerContext> mContext; ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific); }; } // namespace aidl::android::hardware::audio::effect
media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp 0 → 100644 +130 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "LoudnessEnhancerContext.h" namespace aidl::android::hardware::audio::effect { LoudnessEnhancerContext::LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common) : EffectContext(statusDepth, common) { LOG(DEBUG) << __func__; mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; mSampleRate = common.input.base.sampleRate; init_params(); } LoudnessEnhancerContext::~LoudnessEnhancerContext() { LOG(DEBUG) << __func__; mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED; } RetCode LoudnessEnhancerContext::enable() { if (mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) { return RetCode::ERROR_EFFECT_LIB_ERROR; } mState = LOUDNESS_ENHANCER_STATE_ACTIVE; return RetCode::SUCCESS; } RetCode LoudnessEnhancerContext::disable() { if (mState != LOUDNESS_ENHANCER_STATE_ACTIVE) { return RetCode::ERROR_EFFECT_LIB_ERROR; } mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; return RetCode::SUCCESS; } void LoudnessEnhancerContext::reset() { float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification { std::lock_guard lg(mMutex); if (mCompressor != nullptr) { // Get samplingRate from input mCompressor->Initialize(targetAmp, mSampleRate); } } } RetCode LoudnessEnhancerContext::setLeGain(int gainMb) { mGain = gainMb; reset(); // apply parameter update return RetCode::SUCCESS; } IEffect::Status LoudnessEnhancerContext::lvmProcess(float* in, float* out, int samples) { LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples; IEffect::Status status = {EX_NULL_POINTER, 0, 0}; RETURN_VALUE_IF(!in, status, "nullInput"); RETURN_VALUE_IF(!out, status, "nullOutput"); status = {EX_ILLEGAL_STATE, 0, 0}; RETURN_VALUE_IF(getInputFrameSize() != getOutputFrameSize(), status, "FrameSizeMismatch"); auto frameSize = getInputFrameSize(); RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize"); LOG(DEBUG) << __func__ << " start processing"; { std::lock_guard lg(mMutex); // PcmType is always expected to be Float 32 bit. 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, mGain / 2000.0f) * scale; float leftSample, rightSample; if (mCompressor != nullptr) { for (int inIdx = 0; inIdx < samples; inIdx += 2) { // makeup gain is applied on the input of the compressor leftSample = inputAmp * in[inIdx]; rightSample = inputAmp * in[inIdx + 1]; mCompressor->Compress(&leftSample, &rightSample); in[inIdx] = leftSample * inverseScale; in[inIdx + 1] = rightSample * inverseScale; } } else { for (int inIdx = 0; inIdx < samples; inIdx += 2) { leftSample = inputAmp * in[inIdx]; rightSample = inputAmp * in[inIdx + 1]; in[inIdx] = leftSample * inverseScale; in[inIdx + 1] = rightSample * inverseScale; } } bool accumulate = false; if (in != out) { for (int i = 0; i < samples; i++) { if (accumulate) { out[i] += in[i]; } else { out[i] = in[i]; } } } } return {STATUS_OK, samples, samples}; } void LoudnessEnhancerContext::init_params() { mGain = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB; float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification LOG(DEBUG) << __func__ << "Target gain = " << mGain << "mB <=> factor = " << targetAmp; { std::lock_guard lg(mMutex); mCompressor = std::make_unique<le_fx::AdaptiveDynamicRangeCompression>(); mCompressor->Initialize(targetAmp, mSampleRate); } mState = LOUDNESS_ENHANCER_STATE_INITIALIZED; } } // namespace aidl::android::hardware::audio::effect
media/libeffects/loudness/aidl/LoudnessEnhancerContext.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <android-base/thread_annotations.h> #include <audio_effects/effect_loudnessenhancer.h> #include "dsp/core/dynamic_range_compression.h" #include "effect-impl/EffectContext.h" namespace aidl::android::hardware::audio::effect { enum LoudnessEnhancerState { LOUDNESS_ENHANCER_STATE_UNINITIALIZED, LOUDNESS_ENHANCER_STATE_INITIALIZED, LOUDNESS_ENHANCER_STATE_ACTIVE, }; class LoudnessEnhancerContext final : public EffectContext { public: LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common); ~LoudnessEnhancerContext(); RetCode enable(); RetCode disable(); void reset(); RetCode setLeGain(int gainMb); int getLeGain() const { return mGain; } IEffect::Status lvmProcess(float* in, float* out, int samples); private: std::mutex mMutex; LoudnessEnhancerState mState; int mSampleRate; int mGain; // In this implementation, there is no coupling between the compression on the left and right // channels std::unique_ptr<le_fx::AdaptiveDynamicRangeCompression> mCompressor GUARDED_BY(mMutex); void init_params(); }; } // namespace aidl::android::hardware::audio::effect