1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cstddef>
18 
19 #define LOG_TAG "ReverbContext"
20 #include <android-base/logging.h>
21 #include <Utils.h>
22 #include <audio_utils/primitives.h>
23 
24 #include "ReverbContext.h"
25 #include "VectorArithmetic.h"
26 #include "math.h"
27 
28 namespace aidl::android::hardware::audio::effect {
29 
30 using aidl::android::media::audio::common::AudioDeviceDescription;
31 using aidl::android::media::audio::common::AudioDeviceType;
32 
33 #define GOTO_IF_LVREV_ERROR(status, tag, log)                                     \
34     do {                                                                          \
35         LVREV_ReturnStatus_en temp = (status);                                    \
36         if (temp != LVREV_SUCCESS) {                                              \
37             LOG(ERROR) << __func__ << " return status: " << temp << " " << (log); \
38             goto tag;                                                             \
39         }                                                                         \
40     } while (0)
41 
init()42 RetCode ReverbContext::init() {
43     if (isPreset()) {
44         // force reloading preset at first call to process()
45         mPreset = PresetReverb::Presets::NONE;
46         mNextPreset = PresetReverb::Presets::NONE;
47     }
48 
49     mVolume.left = kUnitVolume;
50     mVolume.right = kUnitVolume;
51     mPrevVolume.left = kUnitVolume;
52     mPrevVolume.right = kUnitVolume;
53     volumeMode = VOLUME_FLAT;
54 
55     mSamplesToExitCount = kDefaultDecayTime * mCommon.input.base.sampleRate / 1000;
56 
57     /* Saved strength is used to return the exact strength that was used in the set to the get
58      * because we map the original strength range of 0:1000 to 1:15, and this will avoid
59      * quantisation like effect when returning
60      */
61     mRoomLevel = lvm::kMinLevel;
62     mRoomHfLevel = 0;
63     mEnabled = LVM_FALSE;
64     mDecayTime = kDefaultDecayTime;
65     mDecayHfRatio = kDefaultDamping * 20;
66     mDensity = kDefaultRoomSize * 10;
67     mDiffusion = kDefaultDensity * 10;
68     mLevel = lvm::kMinLevel;
69 
70     // allocate lvm reverb instance
71     LVREV_ReturnStatus_en status = LVREV_SUCCESS;
72     LVREV_InstanceParams_st params = {
73             .MaxBlockSize = lvm::kMaxCallSize,
74             // Max format, could be mono during process
75             .SourceFormat = LVM_STEREO,
76             .NumDelays = LVREV_DELAYLINES_4,
77     };
78     /* Init sets the instance handle */
79     status = LVREV_GetInstanceHandle(&mInstance, &params);
80     GOTO_IF_LVREV_ERROR(status, deinit, "LVREV_GetInstanceHandleFailed");
81 
82     // set control
83     LVREV_ControlParams_st controlParams;
84     initControlParameter(controlParams);
85     status = LVREV_SetControlParameters(mInstance, &controlParams);
86     GOTO_IF_LVREV_ERROR(status, deinit, "LVREV_SetControlParametersFailed");
87 
88     return RetCode::SUCCESS;
89 
90 deinit:
91     deInit();
92     return RetCode::ERROR_EFFECT_LIB_ERROR;
93 }
94 
deInit()95 void ReverbContext::deInit() {
96     if (mInstance) {
97         LVREV_FreeInstance(mInstance);
98         mInstance = nullptr;
99     }
100 }
101 
enable()102 RetCode ReverbContext::enable() {
103     if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
104     mEnabled = true;
105     mSamplesToExitCount = (mDecayTime * mCommon.input.base.sampleRate) / 1000;
106     // force no volume ramp for first buffer processed after enabling the effect
107     volumeMode = VOLUME_FLAT;
108     return RetCode::SUCCESS;
109 }
110 
disable()111 RetCode ReverbContext::disable() {
112     if (!mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
113     mEnabled = false;
114     return RetCode::SUCCESS;
115 }
116 
isAuxiliary()117 bool ReverbContext::isAuxiliary() {
118     return (mType == lvm::ReverbEffectType::AUX_ENV || mType == lvm::ReverbEffectType::AUX_PRESET);
119 }
120 
isPreset()121 bool ReverbContext::isPreset() {
122     return (mType == lvm::ReverbEffectType::AUX_PRESET ||
123             mType == lvm::ReverbEffectType::INSERT_PRESET);
124 }
125 
setVolumeStereo(const Parameter::VolumeStereo & volume)126 RetCode ReverbContext::setVolumeStereo(const Parameter::VolumeStereo& volume) {
127     if (volumeMode == VOLUME_OFF) {
128         // force no volume ramp for first buffer processed after getting volume control
129         volumeMode = VOLUME_FLAT;
130     }
131     mVolumeStereo = volume;
132     return RetCode::SUCCESS;
133 }
134 
setPresetReverbPreset(const PresetReverb::Presets & preset)135 RetCode ReverbContext::setPresetReverbPreset(const PresetReverb::Presets& preset) {
136     mNextPreset = preset;
137     return RetCode::SUCCESS;
138 }
139 
setEnvironmentalReverbRoomLevel(int roomLevel)140 RetCode ReverbContext::setEnvironmentalReverbRoomLevel(int roomLevel) {
141     // Update Control Parameter
142     LVREV_ControlParams_st params;
143     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
144                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
145 
146     // Sum of room and reverb level controls
147     // needs to subtract max levels for both room level and reverb level
148     int combinedLevel = (roomLevel + mLevel) - lvm::kMaxReverbLevel;
149     params.Level = convertLevel(combinedLevel);
150 
151     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
152                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
153     mRoomLevel = roomLevel;
154     return RetCode::SUCCESS;
155 }
156 
setEnvironmentalReverbRoomHfLevel(int roomHfLevel)157 RetCode ReverbContext::setEnvironmentalReverbRoomHfLevel(int roomHfLevel) {
158     // Update Control Parameter
159     LVREV_ControlParams_st params;
160     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
161                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
162 
163     params.LPF = convertHfLevel(roomHfLevel);
164 
165     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
166                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
167     mRoomHfLevel = roomHfLevel;
168     return RetCode::SUCCESS;
169 }
170 
setEnvironmentalReverbDecayTime(int decayTime)171 RetCode ReverbContext::setEnvironmentalReverbDecayTime(int decayTime) {
172     int time = decayTime;
173     if (time > lvm::kMaxT60) {
174         time = lvm::kMaxT60;
175     }
176 
177     // Update Control Parameter
178     LVREV_ControlParams_st params;
179     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
180                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
181 
182     params.T60 = (LVM_UINT16)time;
183     mSamplesToExitCount = (params.T60 * mCommon.input.base.sampleRate) / 1000;
184 
185     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
186                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
187 
188     mDecayTime = time;
189     return RetCode::SUCCESS;
190 }
191 
setEnvironmentalReverbDecayHfRatio(int decayHfRatio)192 RetCode ReverbContext::setEnvironmentalReverbDecayHfRatio(int decayHfRatio) {
193     // Update Control Parameter
194     LVREV_ControlParams_st params;
195     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
196                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
197 
198     params.Damping = (LVM_INT16)(decayHfRatio / 20);
199 
200     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
201                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
202     mDecayHfRatio = decayHfRatio;
203     return RetCode::SUCCESS;
204 }
205 
setEnvironmentalReverbLevel(int level)206 RetCode ReverbContext::setEnvironmentalReverbLevel(int level) {
207     // Update Control Parameter
208     LVREV_ControlParams_st params;
209     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
210                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
211 
212     // Sum of room and reverb level controls
213     // needs to subtract max levels for both room level and level
214     int combinedLevel = (level + mRoomLevel) - lvm::kMaxReverbLevel;
215     params.Level = convertLevel(combinedLevel);
216 
217     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
218                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
219 
220     mLevel = level;
221     return RetCode::SUCCESS;
222 }
223 
setEnvironmentalReverbDelay(int delay)224 RetCode ReverbContext::setEnvironmentalReverbDelay(int delay) {
225     mDelay = delay;
226     return RetCode::SUCCESS;
227 }
228 
setEnvironmentalReverbDiffusion(int diffusion)229 RetCode ReverbContext::setEnvironmentalReverbDiffusion(int diffusion) {
230     // Update Control Parameter
231     LVREV_ControlParams_st params;
232     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
233                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
234 
235     params.Density = (LVM_INT16)(diffusion / 10);
236 
237     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
238                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
239 
240     mDiffusion = diffusion;
241     return RetCode::SUCCESS;
242 }
243 
setEnvironmentalReverbDensity(int density)244 RetCode ReverbContext::setEnvironmentalReverbDensity(int density) {
245     // Update Control Parameter
246     LVREV_ControlParams_st params;
247     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, &params),
248                     RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
249 
250     params.RoomSize = (LVM_INT16)(((density * 99) / 1000) + 1);
251 
252     RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, &params),
253                     RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
254 
255     mDensity = density;
256     return RetCode::SUCCESS;
257 }
258 
setEnvironmentalReverbBypass(bool bypass)259 RetCode ReverbContext::setEnvironmentalReverbBypass(bool bypass) {
260     mBypass = bypass;
261     return RetCode::SUCCESS;
262 }
263 
loadPreset()264 void ReverbContext::loadPreset() {
265     // TODO: add delay when early reflections are implemented
266     mPreset = mNextPreset;
267 
268     if (mPreset != PresetReverb::Presets::NONE) {
269         const t_reverb_settings preset = mReverbPresets[mPreset];
270         setEnvironmentalReverbRoomLevel(preset.roomLevel);
271         setEnvironmentalReverbRoomHfLevel(preset.roomHFLevel);
272         setEnvironmentalReverbDecayTime(preset.decayTime);
273         setEnvironmentalReverbDecayHfRatio(preset.decayHFRatio);
274         setEnvironmentalReverbLevel(preset.reverbLevel);
275         // reverbDelay
276         setEnvironmentalReverbDiffusion(preset.diffusion);
277         setEnvironmentalReverbDensity(preset.density);
278     }
279 }
280 
initControlParameter(LVREV_ControlParams_st & params)281 void ReverbContext::initControlParameter(LVREV_ControlParams_st& params) {
282     /* Set the initial process parameters */
283     /* General parameters */
284     params.OperatingMode = LVM_MODE_ON;
285     params.SampleRate = LVM_FS_44100;
286     params.SourceFormat = (::aidl::android::hardware::audio::common::getChannelCount(
287                                    mCommon.input.base.channelMask) == 1
288                                    ? LVM_MONO
289                                    : LVM_STEREO);
290 
291     if (!isAuxiliary() && params.SourceFormat == LVM_MONO) {
292         params.SourceFormat = LVM_STEREO;
293     }
294 
295     /* Reverb parameters */
296     params.Level = kDefaultLevel;
297     params.LPF = kDefaultLPF;
298     params.HPF = kDefaultHPF;
299     params.T60 = kDefaultDecayTime;
300     params.Density = kDefaultDensity;
301     params.Damping = kDefaultDamping;
302     params.RoomSize = kDefaultRoomSize;
303 }
304 
305 /*
306  * Convert level from OpenSL ES format to LVM format
307  *
308  *  @param level : level to be applied
309  */
310 
convertLevel(int level)311 int ReverbContext::convertLevel(int level) {
312     for (std::size_t i = 0; i < kLevelMapping.size(); i++) {
313         if (level <= kLevelMapping[i]) {
314             return i;
315         }
316     }
317     return kDefaultLevel;
318 }
319 
320 /*
321  * Convert level HF from OpenSL ES format to LVM format
322  *
323  * @param hfLevel : level to be applied
324  */
325 
convertHfLevel(int hfLevel)326 int16_t ReverbContext::convertHfLevel(int hfLevel) {
327     for (auto lpfPair : kLPFMapping) {
328         if (hfLevel <= lpfPair.roomHf) {
329             return lpfPair.lpf;
330         }
331     }
332     return kDefaultLPF;
333 }
334 
process(float * in,float * out,int samples)335 IEffect::Status ReverbContext::process(float* in, float* out, int samples) {
336     IEffect::Status status = {EX_NULL_POINTER, 0, 0};
337     RETURN_VALUE_IF(!in, status, "nullInput");
338     RETURN_VALUE_IF(!out, status, "nullOutput");
339     status = {EX_ILLEGAL_STATE, 0, 0};
340     int64_t inputFrameCount = getCommon().input.frameCount;
341     int64_t outputFrameCount = getCommon().output.frameCount;
342     RETURN_VALUE_IF(inputFrameCount != outputFrameCount, status, "FrameCountMismatch");
343     RETURN_VALUE_IF(0 == getInputFrameSize(), status, "zeroFrameSize");
344 
345     int channels = ::aidl::android::hardware::audio::common::getChannelCount(
346             mCommon.input.base.channelMask);
347     int outChannels = ::aidl::android::hardware::audio::common::getChannelCount(
348             mCommon.output.base.channelMask);
349     int frameCount = mCommon.input.frameCount;
350 
351     if (mBypass) {
352         if (isAuxiliary()) {
353             memset(out, 0, getOutputFrameSize() * frameCount);
354         } else {
355             memcpy_to_float_from_float_with_clamping(out, in, samples, 1);
356         }
357         return {STATUS_OK, samples, outChannels * frameCount};
358     }
359 
360     // Reverb only effects the stereo channels in multichannel source.
361     if (channels < 1 || channels > LVM_MAX_CHANNELS) {
362         LOG(ERROR) << __func__ << " process invalid PCM channels " << channels;
363         return status;
364     }
365 
366     std::vector<float> inputSamples;
367     std::vector<float> outputSamples(frameCount * FCC_2);
368 
369     if (isPreset() && mNextPreset != mPreset) {
370         loadPreset();
371     }
372 
373     if (isAuxiliary()) {
374         inputSamples.resize(samples);
375         inputSamples.assign(in, in + samples);
376     } else {
377         // Resizing to stereo is required to duplicate mono input
378         inputSamples.resize(frameCount * FCC_2);
379         if (channels >= FCC_2) {
380             for (int i = 0; i < frameCount; i++) {
381                 inputSamples[FCC_2 * i] = in[channels * i] * kSendLevel;
382                 inputSamples[FCC_2 * i + 1] = in[channels * i + 1] * kSendLevel;
383             }
384         } else {
385             for (int i = 0; i < frameCount; i++) {
386                 inputSamples[FCC_2 * i] = inputSamples[FCC_2 * i + 1] = in[i] * kSendLevel;
387             }
388         }
389     }
390 
391     if (isPreset() && mPreset == PresetReverb::Presets::NONE) {
392         std::fill(outputSamples.begin(), outputSamples.end(), 0);  // always stereo here
393     } else {
394         if (!mEnabled && mSamplesToExitCount > 0) {
395             std::fill(outputSamples.begin(), outputSamples.end(), 0);
396         }
397         int inputBufferIndex = 0;
398         int outputBufferIndex = 0;
399 
400         // LVREV library supports max of int16_t frames at a time
401         constexpr int kMaxBlockFrames = std::numeric_limits<int16_t>::max();
402         const auto inputFrameSize = getInputFrameSize();
403         const auto outputFrameSize = getOutputFrameSize();
404 
405         /* Process the samples, producing a stereo output */
406         for (int fc = frameCount; fc > 0;) {
407             int processFrames = std::min(fc, kMaxBlockFrames);
408             LVREV_ReturnStatus_en lvrevStatus =
409                     LVREV_Process(mInstance,                            /* Instance handle */
410                                   inputSamples.data() + inputBufferIndex,   /* Input buffer */
411                                   outputSamples.data() + outputBufferIndex, /* Output buffer */
412                                   processFrames); /* Number of samples to process */
413             if (lvrevStatus != LVREV_SUCCESS) {
414                 LOG(ERROR) << __func__ << " LVREV_Process error: " << lvrevStatus;
415                 return {EX_UNSUPPORTED_OPERATION, 0, 0};
416             }
417 
418             fc -= processFrames;
419 
420             inputBufferIndex += processFrames * inputFrameSize / sizeof(float);
421             outputBufferIndex += processFrames * outputFrameSize / sizeof(float);
422         }
423     }
424     // Convert to 16 bits
425     if (isAuxiliary()) {
426         // nothing to do here
427     } else {
428         if (channels >= FCC_2) {
429             for (int i = 0; i < frameCount; i++) {
430                 // Mix with dry input
431                 outputSamples[FCC_2 * i] += in[channels * i];
432                 outputSamples[FCC_2 * i + 1] += in[channels * i + 1];
433             }
434         } else {
435             for (int i = 0; i < frameCount; i++) {
436                 // Mix with dry input
437                 outputSamples[FCC_2 * i] += in[i];
438                 outputSamples[FCC_2 * i + 1] += in[i];
439             }
440         }
441 
442         // apply volume with ramp if needed
443         if (mVolume != mPrevVolume && volumeMode == VOLUME_RAMP) {
444             float vl = mPrevVolume.left;
445             float incl = (mVolume.left - vl) / frameCount;
446             float vr = mPrevVolume.right;
447             float incr = (mVolume.right - vr) / frameCount;
448 
449             for (int i = 0; i < frameCount; i++) {
450                 outputSamples[FCC_2 * i] *= vl;
451                 outputSamples[FCC_2 * i + 1] *= vr;
452 
453                 vl += incl;
454                 vr += incr;
455             }
456             mPrevVolume = mVolume;
457         } else if (volumeMode != VOLUME_OFF) {
458             if (mVolume.left != kUnitVolume || mVolume.right != kUnitVolume) {
459                 for (int i = 0; i < frameCount; i++) {
460                     outputSamples[FCC_2 * i] *= mVolume.left;
461                     outputSamples[FCC_2 * i + 1] *= mVolume.right;
462                 }
463             }
464             mPrevVolume = mVolume;
465             volumeMode = VOLUME_RAMP;
466         }
467     }
468 
469     if (outChannels > 2) {
470         for (int i = 0; i < frameCount; i++) {
471             out[outChannels * i] = outputSamples[FCC_2 * i];
472             out[outChannels * i + 1] = outputSamples[FCC_2 * i + 1];
473         }
474         if (!isAuxiliary()) {
475             for (int i = 0; i < frameCount; i++) {
476                 // channels and outChannels are expected to be same.
477                 for (int j = FCC_2; j < outChannels; j++) {
478                     out[outChannels * i + j] = in[outChannels * i + j];
479                 }
480             }
481         }
482     } else {
483         if (outChannels == FCC_1) {
484             From2iToMono_Float(outputSamples.data(), out, frameCount);
485         } else {
486             for (int i = 0; i < frameCount * FCC_2; i++) {
487                 out[i] = outputSamples[i];
488             }
489         }
490     }
491 
492     if (!mEnabled && mSamplesToExitCount > 0) {
493         // signed - unsigned will trigger integer overflow if result becomes negative.
494         mSamplesToExitCount -= samples;
495     }
496 
497     return {STATUS_OK, samples, outChannels * frameCount};
498 }
499 
500 }  // namespace aidl::android::hardware::audio::effect
501