1 /*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /****************************************************************************************/
19 /* */
20 /* Includes */
21 /* */
22 /****************************************************************************************/
23
24 #include <system/audio.h>
25 #include "LVREV_Private.h"
26 #include "Filter.h"
27
28 /****************************************************************************************/
29 /* */
30 /* FUNCTION: LVREV_ApplyNewSettings */
31 /* */
32 /* DESCRIPTION: */
33 /* Applies the new control parameters */
34 /* */
35 /* PARAMETERS: */
36 /* pPrivate Pointer to the instance private parameters */
37 /* */
38 /* RETURNS: */
39 /* LVREV_Success Succeeded */
40 /* LVREV_NULLADDRESS When pPrivate is NULL */
41 /* */
42 /* NOTES: */
43 /* */
44 /****************************************************************************************/
45
LVREV_ApplyNewSettings(LVREV_Instance_st * pPrivate)46 LVREV_ReturnStatus_en LVREV_ApplyNewSettings(LVREV_Instance_st* pPrivate) {
47 LVM_Mode_en OperatingMode;
48 LVM_INT32 NumberOfDelayLines;
49
50 /* Check for NULL pointer */
51 if (pPrivate == LVM_NULL) {
52 return LVREV_NULLADDRESS;
53 }
54
55 OperatingMode = pPrivate->NewParams.OperatingMode;
56
57 if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) {
58 NumberOfDelayLines = 4;
59 } else if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2) {
60 NumberOfDelayLines = 2;
61 } else {
62 NumberOfDelayLines = 1;
63 }
64
65 /*
66 * Update the high pass filter coefficients
67 */
68 if ((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
69 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
70 (pPrivate->bFirstControl == LVM_TRUE)) {
71 LVM_FLOAT Omega;
72 FO_FLOAT_Coefs_t Coeffs;
73
74 Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
75 LVM_FO_HPF(Omega, &Coeffs);
76 const std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
77 Coeffs.A0, Coeffs.A1, 0.0, -(Coeffs.B1), 0.0};
78 pPrivate->pRevHPFBiquad.reset(
79 new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1, coefs));
80 }
81
82 /*
83 * Update the low pass filter coefficients
84 */
85 if ((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
86 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
87 (pPrivate->bFirstControl == LVM_TRUE)) {
88 LVM_FLOAT Omega;
89 FO_FLOAT_Coefs_t Coeffs;
90
91 Coeffs.A0 = 1;
92 Coeffs.A1 = 0;
93 Coeffs.B1 = 0;
94 if (pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1)) {
95 Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
96
97 /*
98 * Do not apply filter if w =2*pi*fc/fs >= 2.9
99 */
100 if (Omega <= (LVM_FLOAT)LVREV_2_9_INQ29) {
101 LVM_FO_LPF(Omega, &Coeffs);
102 }
103 }
104 const std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
105 Coeffs.A0, Coeffs.A1, 0.0, -(Coeffs.B1), 0.0};
106 pPrivate->pRevLPFBiquad.reset(
107 new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1, coefs));
108 }
109
110 /*
111 * Calculate the room size parameter
112 */
113 if (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) {
114 /* Room size range is 10ms to 200ms
115 * 0% -- 10ms
116 * 50% -- 65ms
117 * 100% -- 120ms
118 */
119 pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize * 11) + 5) / 10);
120 }
121
122 /*
123 * Update the T delay number of samples and the all pass delay number of samples
124 */
125 if ((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
126 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
127 (pPrivate->bFirstControl == LVM_TRUE)) {
128 LVM_UINT32 Temp;
129 LVM_INT32 APDelaySize;
130 LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
131 LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
132 LVM_INT16 i;
133 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
134 LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
135
136 /*
137 * For each delay line
138 */
139 for (i = 0; i < NumberOfDelayLines; i++) {
140 if (i != 0) {
141 LVM_FLOAT Temp1; /* to avoid QAC warning on type conversion */
142
143 Temp1 = (LVM_FLOAT)DelayLengthSamples;
144 Temp = (LVM_UINT32)(Temp1 * ScaleTable[i]);
145 } else {
146 Temp = DelayLengthSamples;
147 }
148 APDelaySize = Temp / 1500;
149
150 /*
151 * Set the fixed delay
152 */
153
154 Temp = (LVREV_MAX_T_DELAY[i] - LVREV_MAX_AP_DELAY[i]) * Fs / 192000;
155 pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
156
157 /*
158 * Set the tap selection
159 */
160 if (pPrivate->AB_Selection) {
161 /* Smooth from tap A to tap B */
162 pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - Temp - APDelaySize];
163 pPrivate->B_DelaySize[i] = APDelaySize;
164 pPrivate->Mixer_APTaps[i].Target1 = 0;
165 pPrivate->Mixer_APTaps[i].Target2 = 1.0f;
166 } else {
167 /* Smooth from tap B to tap A */
168 pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - Temp - APDelaySize];
169 pPrivate->A_DelaySize[i] = APDelaySize;
170 pPrivate->Mixer_APTaps[i].Target2 = 0;
171 pPrivate->Mixer_APTaps[i].Target1 = 1.0f;
172 }
173
174 /*
175 * Set the maximum block size to the smallest delay size
176 */
177 pPrivate->MaxBlkLen = Temp;
178 if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i]) {
179 pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
180 }
181 if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i]) {
182 pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
183 }
184 }
185 if (pPrivate->AB_Selection) {
186 pPrivate->AB_Selection = 0;
187 } else {
188 pPrivate->AB_Selection = 1;
189 }
190
191 /*
192 * Limit the maximum block length
193 */
194 /* Just as a precausion, but no problem if we remove this line */
195 pPrivate->MaxBlkLen = pPrivate->MaxBlkLen - 2;
196 if (pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize) {
197 pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
198 }
199 }
200
201 /*
202 * Update the low pass filter coefficient
203 */
204 if ((pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
205 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
206 (pPrivate->bFirstControl == LVM_TRUE)) {
207 LVM_INT32 Temp;
208 LVM_FLOAT Omega;
209 FO_FLOAT_Coefs_t Coeffs;
210 LVM_INT16 i;
211 LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
212 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4,
213 LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
214
215 /*
216 * For each filter
217 */
218 for (i = 0; i < NumberOfDelayLines; i++) {
219 if (i != 0) {
220 Temp = (LVM_INT32)(ScaleTable[i] * Damping);
221 } else {
222 Temp = Damping;
223 }
224 if (Temp <= (LVM_INT32)(LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1)) {
225 Omega = LVM_GetOmega(Temp, pPrivate->NewParams.SampleRate);
226 LVM_FO_LPF(Omega, &Coeffs);
227 } else {
228 Coeffs.A0 = 1;
229 Coeffs.A1 = 0;
230 Coeffs.B1 = 0;
231 }
232 const std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
233 Coeffs.A0, Coeffs.A1, 0.0, -(Coeffs.B1), 0.0};
234 pPrivate->revLPFBiquad[i].reset(
235 new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1, coefs));
236 }
237 }
238
239 /*
240 * Update All-pass filter mixer time constants
241 */
242 if ((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
243 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
244 (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density)) {
245 LVM_INT16 i;
246 LVM_FLOAT Alpha;
247 LVM_FLOAT AlphaTap;
248
249 Alpha = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC,
250 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), 1);
251
252 AlphaTap = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC,
253 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), 1);
254
255 for (i = 0; i < 4; i++) {
256 pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
257 pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
258 pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
259 pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
260 }
261 }
262
263 /*
264 * Update the feed back gain
265 */
266 if ((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
267 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
268 (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
269 (pPrivate->bFirstControl == LVM_TRUE)) {
270 LVM_FLOAT G[4]; /* Feedback gain (Q7.24) */
271
272 if (pPrivate->NewParams.T60 == 0) {
273 G[3] = 0;
274 G[2] = 0;
275 G[1] = 0;
276 G[0] = 0;
277 } else {
278 LVM_FLOAT Temp1;
279 LVM_FLOAT Temp2;
280 LVM_INT16 i;
281 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
282 LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
283
284 /*
285 * For each delay line
286 */
287 for (i = 0; i < NumberOfDelayLines; i++) {
288 Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
289 if (Temp1 >= (4)) {
290 G[i] = 0;
291 } else if ((Temp1 >= (2))) {
292 Temp2 = LVM_Power10(-(Temp1 / 2.0f));
293 Temp1 = LVM_Power10(-(Temp1 / 2.0f));
294 Temp1 = Temp1 * Temp2;
295 } else {
296 Temp1 = LVM_Power10(-(Temp1));
297 }
298 if (NumberOfDelayLines == 1) {
299 G[i] = Temp1;
300 } else {
301 LVM_FLOAT TempG;
302 TempG = Temp1 * ONE_OVER_SQRT_TWO;
303 G[i] = TempG;
304 }
305 }
306 }
307
308 /* Set up the feedback mixers for four delay lines */
309 pPrivate->FeedbackMixer[0].Target = G[0];
310 pPrivate->FeedbackMixer[1].Target = G[1];
311 pPrivate->FeedbackMixer[2].Target = G[2];
312 pPrivate->FeedbackMixer[3].Target = G[3];
313 }
314
315 /*
316 * Calculate the gain correction
317 */
318 if ((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
319 (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
320 (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60)) {
321 LVM_INT32 Index = 0;
322 LVM_FLOAT Index_FLOAT;
323 LVM_INT32 i = 0;
324 LVM_FLOAT Gain = 0;
325 LVM_INT32 RoomSize = 0;
326 LVM_FLOAT T60;
327 LVM_FLOAT Coefs[5];
328
329 if (pPrivate->NewParams.RoomSize == 0) {
330 RoomSize = 1;
331 } else {
332 RoomSize = (LVM_INT32)pPrivate->NewParams.RoomSize;
333 }
334
335 if (pPrivate->NewParams.T60 < 100) {
336 T60 = 100 * LVREV_T60_SCALE;
337 } else {
338 T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
339 }
340
341 /* Find the nearest room size in table */
342 for (i = 0; i < 24; i++) {
343 if (RoomSize <= LVREV_GainPolyTable[i][0]) {
344 Index = i;
345 break;
346 }
347 }
348
349 if (RoomSize == LVREV_GainPolyTable[Index][0]) {
350 /* Take table values if the room size is in table */
351 for (i = 1; i < 5; i++) {
352 Coefs[i - 1] = LVREV_GainPolyTable[Index][i];
353 }
354 Coefs[4] = 0;
355 Gain = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
356 } else {
357 /* Interpolate the gain between nearest room sizes */
358
359 LVM_FLOAT Gain1, Gain2;
360 LVM_INT32 Tot_Dist, Dist;
361
362 Tot_Dist = (LVM_UINT32)LVREV_GainPolyTable[Index][0] -
363 (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
364 Dist = RoomSize - (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
365
366 /* Get gain for first */
367 for (i = 1; i < 5; i++) {
368 Coefs[i - 1] = LVREV_GainPolyTable[Index - 1][i];
369 }
370 Coefs[4] = 0;
371
372 Gain1 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
373
374 /* Get gain for second */
375 for (i = 1; i < 5; i++) {
376 Coefs[i - 1] = LVREV_GainPolyTable[Index][i];
377 }
378 Coefs[4] = 0;
379
380 Gain2 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
381
382 /* Linear Interpolate the gain */
383 Gain = Gain1 + (((Gain2 - Gain1) * Dist) / (Tot_Dist));
384 }
385
386 /*
387 * Get the inverse of gain: Q.15
388 * Gain is mostly above one except few cases, take only gains above 1
389 */
390 if (Gain < 1) {
391 pPrivate->Gain = 1;
392 } else {
393 pPrivate->Gain = 1 / Gain;
394 }
395
396 Index_FLOAT = 100.0f / (LVM_FLOAT)(100 + pPrivate->NewParams.Level);
397 pPrivate->Gain = pPrivate->Gain * Index_FLOAT;
398 pPrivate->GainMixer.Target = (pPrivate->Gain * Index_FLOAT) / 2;
399 }
400
401 /*
402 * Update the all pass comb filter coefficient
403 */
404 if ((pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
405 (pPrivate->bFirstControl == LVM_TRUE)) {
406 LVM_INT16 i;
407 LVM_FLOAT b = (LVM_FLOAT)pPrivate->NewParams.Density * LVREV_B_8_on_1000;
408
409 for (i = 0; i < 4; i++) {
410 pPrivate->Mixer_SGFeedback[i].Target = b;
411 pPrivate->Mixer_SGFeedforward[i].Target = b;
412 }
413 }
414
415 /*
416 * Update the bypass mixer time constant
417 */
418 if ((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
419 (pPrivate->bFirstControl == LVM_TRUE)) {
420 LVM_UINT16 NumChannels = 1; /* Assume MONO format */
421 LVM_FLOAT Alpha;
422
423 Alpha = LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC,
424 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
425 NumChannels);
426 pPrivate->FeedbackMixer[0].Alpha = Alpha;
427 pPrivate->FeedbackMixer[1].Alpha = Alpha;
428 pPrivate->FeedbackMixer[2].Alpha = Alpha;
429 pPrivate->FeedbackMixer[3].Alpha = Alpha;
430
431 NumChannels = 2; /* Always stereo output */
432 pPrivate->BypassMixer.Alpha1 = LVM_Mixer_TimeConstant(
433 LVREV_BYPASSMIXER_TC, LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
434 NumChannels);
435 pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
436 pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
437 }
438
439 /*
440 * Update the bypass mixer targets
441 */
442 if ((pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
443 (pPrivate->NewParams.OperatingMode == LVM_MODE_ON)) {
444 pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level) / 100.0f;
445 pPrivate->BypassMixer.Target1 = 0x00000000;
446 if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE)) {
447 pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
448 }
449 if (pPrivate->NewParams.Level != 0) {
450 pPrivate->bDisableReverb = LVM_FALSE;
451 }
452 }
453
454 if (pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode) {
455 if (pPrivate->NewParams.OperatingMode == LVM_MODE_ON) {
456 pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level) / 100.0f;
457 pPrivate->BypassMixer.Target1 = 0x00000000;
458
459 pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
460 OperatingMode = LVM_MODE_ON;
461 if (pPrivate->NewParams.Level == 0) {
462 pPrivate->bDisableReverb = LVM_TRUE;
463 } else {
464 pPrivate->bDisableReverb = LVM_FALSE;
465 }
466 } else if (pPrivate->bFirstControl == LVM_FALSE) {
467 pPrivate->BypassMixer.Target2 = 0x00000000;
468 pPrivate->BypassMixer.Target1 = 0x00000000;
469 pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
470 pPrivate->GainMixer.Target = 0.03125f;
471 OperatingMode = LVM_MODE_ON;
472 } else {
473 OperatingMode = LVM_MODE_OFF;
474 }
475 }
476
477 /* If it is the first call to ApplyNew settings force the current to the target \
478 to begin immediate playback of the effect */
479 if (pPrivate->bFirstControl == LVM_TRUE) {
480 pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
481 pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
482 }
483
484 /*
485 * Copy the new parameters
486 */
487 pPrivate->CurrentParams = pPrivate->NewParams;
488 pPrivate->CurrentParams.OperatingMode = OperatingMode;
489
490 /*
491 * Update flag
492 */
493 if (pPrivate->bFirstControl == LVM_TRUE) {
494 pPrivate->bFirstControl = LVM_FALSE;
495 }
496
497 return LVREV_SUCCESS;
498 }
499 /****************************************************************************************/
500 /* */
501 /* FUNCTION: BypassMixer_Callback */
502 /* */
503 /* DESCRIPTION: */
504 /* Controls the On to Off operating mode transition */
505 /* */
506 /* PARAMETERS: */
507 /* pPrivate Pointer to the instance private parameters */
508 /* */
509 /* RETURNS: */
510 /* LVREV_Success Succeeded */
511 /* LVREV_NULLADDRESS When pPrivate is NULL */
512 /* */
513 /* NOTES: */
514 /* */
515 /****************************************************************************************/
BypassMixer_Callback(void * pCallbackData,void * pGeneralPurpose,LVM_INT16 GeneralPurpose)516 LVM_INT32 BypassMixer_Callback(void* pCallbackData, void* pGeneralPurpose,
517 LVM_INT16 GeneralPurpose) {
518 LVREV_Instance_st* pLVREV_Private = (LVREV_Instance_st*)pCallbackData;
519
520 /*
521 * Avoid build warnings
522 */
523 (void)pGeneralPurpose;
524 (void)GeneralPurpose;
525
526 /*
527 * Turn off
528 */
529 pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_OFF;
530 pLVREV_Private->bDisableReverb = LVM_TRUE;
531 LVREV_ClearAudioBuffers((LVREV_Handle_t)pCallbackData);
532
533 return 0;
534 }
535
536 /* End of file */
537