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, ¶ms);
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, ¶ms),
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, ¶ms),
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, ¶ms),
161 RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
162
163 params.LPF = convertHfLevel(roomHfLevel);
164
165 RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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, ¶ms),
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