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 #include "LVREV_Private.h"
24 #include "Filter.h"
25
26 /****************************************************************************************/
27 /* */
28 /* FUNCTION: LVREV_ApplyNewSettings */
29 /* */
30 /* DESCRIPTION: */
31 /* Applies the new control parameters */
32 /* */
33 /* PARAMETERS: */
34 /* pPrivate Pointer to the instance private parameters */
35 /* */
36 /* RETURNS: */
37 /* LVREV_Success Succeeded */
38 /* LVREV_NULLADDRESS When pPrivate is NULL */
39 /* */
40 /* NOTES: */
41 /* */
42 /****************************************************************************************/
43
LVREV_ApplyNewSettings(LVREV_Instance_st * pPrivate)44 LVREV_ReturnStatus_en LVREV_ApplyNewSettings (LVREV_Instance_st *pPrivate)
45 {
46
47 LVM_Mode_en OperatingMode;
48 LVM_INT32 NumberOfDelayLines;
49
50 /* Check for NULL pointer */
51 if(pPrivate == LVM_NULL)
52 {
53 return LVREV_NULLADDRESS;
54 }
55
56 OperatingMode = pPrivate->NewParams.OperatingMode;
57
58 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
59 {
60 NumberOfDelayLines = 4;
61 }
62 else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
63 {
64 NumberOfDelayLines = 2;
65 }
66 else
67 {
68 NumberOfDelayLines = 1;
69 }
70
71 /*
72 * Update the high pass filter coefficients
73 */
74 if((pPrivate->NewParams.HPF != pPrivate->CurrentParams.HPF) ||
75 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
76 (pPrivate->bFirstControl == LVM_TRUE))
77 {
78 LVM_FLOAT Omega;
79 FO_FLOAT_Coefs_t Coeffs;
80
81 Omega = LVM_GetOmega(pPrivate->NewParams.HPF, pPrivate->NewParams.SampleRate);
82 LVM_FO_HPF(Omega, &Coeffs);
83 FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs,
84 &pPrivate->pFastData->HPTaps, &Coeffs);
85 LoadConst_Float(0,
86 (LVM_FLOAT *)&pPrivate->pFastData->HPTaps,
87 sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
88 }
89
90 /*
91 * Update the low pass filter coefficients
92 */
93 if((pPrivate->NewParams.LPF != pPrivate->CurrentParams.LPF) ||
94 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
95 (pPrivate->bFirstControl == LVM_TRUE))
96 {
97 LVM_FLOAT Omega;
98 FO_FLOAT_Coefs_t Coeffs;
99
100 Coeffs.A0 = 1;
101 Coeffs.A1 = 0;
102 Coeffs.B1 = 0;
103 if(pPrivate->NewParams.LPF <= (LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
104 {
105 Omega = LVM_GetOmega(pPrivate->NewParams.LPF, pPrivate->NewParams.SampleRate);
106
107 /*
108 * Do not apply filter if w =2*pi*fc/fs >= 2.9
109 */
110 if(Omega <= (LVM_FLOAT)LVREV_2_9_INQ29)
111 {
112 LVM_FO_LPF(Omega, &Coeffs);
113 }
114 }
115 FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs,
116 &pPrivate->pFastData->LPTaps, &Coeffs);
117 LoadConst_Float(0,
118 (LVM_FLOAT *)&pPrivate->pFastData->LPTaps,
119 sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
120 }
121
122 /*
123 * Calculate the room size parameter
124 */
125 if( pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize)
126 {
127 /* Room size range is 10ms to 200ms
128 * 0% -- 10ms
129 * 50% -- 65ms
130 * 100% -- 120ms
131 */
132 pPrivate->RoomSizeInms = 10 + (((pPrivate->NewParams.RoomSize*11) + 5) / 10);
133 }
134
135 /*
136 * Update the T delay number of samples and the all pass delay number of samples
137 */
138 if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
139 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
140 (pPrivate->bFirstControl == LVM_TRUE))
141 {
142
143 LVM_UINT32 Temp;
144 LVM_INT32 APDelaySize;
145 LVM_INT32 Fs = LVM_GetFsFromTable(pPrivate->NewParams.SampleRate);
146 LVM_UINT32 DelayLengthSamples = (LVM_UINT32)(Fs * pPrivate->RoomSizeInms);
147 LVM_INT16 i;
148 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4, \
149 LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
150 LVM_INT16 MaxT_Delay[] = {LVREV_MAX_T0_DELAY, LVREV_MAX_T1_DELAY, \
151 LVREV_MAX_T2_DELAY, LVREV_MAX_T3_DELAY};
152 LVM_INT16 MaxAP_Delay[] = {LVREV_MAX_AP0_DELAY, LVREV_MAX_AP1_DELAY, \
153 LVREV_MAX_AP2_DELAY, LVREV_MAX_AP3_DELAY};
154
155 /*
156 * For each delay line
157 */
158 for (i = 0; i < NumberOfDelayLines; i++)
159 {
160 if (i != 0)
161 {
162 LVM_FLOAT Temp1; /* to avoid QAC warning on type conversion */
163
164 Temp1=(LVM_FLOAT)DelayLengthSamples;
165 Temp = (LVM_UINT32)(Temp1 * ScaleTable[i]);
166 }
167 else
168 {
169 Temp = DelayLengthSamples;
170 }
171 APDelaySize = Temp / 1500;
172
173 /*
174 * Set the fixed delay
175 */
176
177 Temp = (MaxT_Delay[i] - MaxAP_Delay[i]) * Fs / 192000;
178 pPrivate->Delay_AP[i] = pPrivate->T[i] - Temp;
179
180 /*
181 * Set the tap selection
182 */
183 if (pPrivate->AB_Selection)
184 {
185 /* Smooth from tap A to tap B */
186 pPrivate->pOffsetB[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
187 Temp - APDelaySize];
188 pPrivate->B_DelaySize[i] = APDelaySize;
189 pPrivate->Mixer_APTaps[i].Target1 = 0;
190 pPrivate->Mixer_APTaps[i].Target2 = 1.0f;
191 }
192 else
193 {
194 /* Smooth from tap B to tap A */
195 pPrivate->pOffsetA[i] = &pPrivate->pDelay_T[i][pPrivate->T[i] - \
196 Temp - APDelaySize];
197 pPrivate->A_DelaySize[i] = APDelaySize;
198 pPrivate->Mixer_APTaps[i].Target2 = 0;
199 pPrivate->Mixer_APTaps[i].Target1 = 1.0f;
200 }
201
202 /*
203 * Set the maximum block size to the smallest delay size
204 */
205 pPrivate->MaxBlkLen = Temp;
206 if (pPrivate->MaxBlkLen > pPrivate->A_DelaySize[i])
207 {
208 pPrivate->MaxBlkLen = pPrivate->A_DelaySize[i];
209 }
210 if (pPrivate->MaxBlkLen > pPrivate->B_DelaySize[i])
211 {
212 pPrivate->MaxBlkLen = pPrivate->B_DelaySize[i];
213 }
214 }
215 if (pPrivate->AB_Selection)
216 {
217 pPrivate->AB_Selection = 0;
218 }
219 else
220 {
221 pPrivate->AB_Selection = 1;
222 }
223
224 /*
225 * Limit the maximum block length
226 */
227 /* Just as a precausion, but no problem if we remove this line */
228 pPrivate->MaxBlkLen = pPrivate->MaxBlkLen - 2;
229 if(pPrivate->MaxBlkLen > pPrivate->InstanceParams.MaxBlockSize)
230 {
231 pPrivate->MaxBlkLen = (LVM_INT32)pPrivate->InstanceParams.MaxBlockSize;
232 }
233 }
234
235 /*
236 * Update the low pass filter coefficient
237 */
238 if( (pPrivate->NewParams.Damping != pPrivate->CurrentParams.Damping) ||
239 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
240 (pPrivate->bFirstControl == LVM_TRUE))
241 {
242
243 LVM_INT32 Temp;
244 LVM_FLOAT Omega;
245 FO_FLOAT_Coefs_t Coeffs;
246 LVM_INT16 i;
247 LVM_INT16 Damping = (LVM_INT16)((pPrivate->NewParams.Damping * 100) + 1000);
248 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_0_on_4, LVREV_T_3_Power_1_on_4,
249 LVREV_T_3_Power_2_on_4, LVREV_T_3_Power_3_on_4};
250
251 /*
252 * For each filter
253 */
254 for (i = 0; i < NumberOfDelayLines; i++)
255 {
256 if (i != 0)
257 {
258 Temp = (LVM_INT32)(ScaleTable[i] * Damping);
259 }
260 else
261 {
262 Temp = Damping;
263 }
264 if(Temp <= (LVM_INT32)(LVM_FsTable[pPrivate->NewParams.SampleRate] >> 1))
265 {
266 Omega = LVM_GetOmega(Temp, pPrivate->NewParams.SampleRate);
267 LVM_FO_LPF(Omega, &Coeffs);
268 }
269 else
270 {
271 Coeffs.A0 = 1;
272 Coeffs.A1 = 0;
273 Coeffs.B1 = 0;
274 }
275 FO_1I_D32F32Cll_TRC_WRA_01_Init(&pPrivate->pFastCoef->RevLPCoefs[i],
276 &pPrivate->pFastData->RevLPTaps[i], &Coeffs);
277 }
278 }
279
280 /*
281 * Update All-pass filter mixer time constants
282 */
283 if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
284 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
285 (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density))
286 {
287 LVM_INT16 i;
288 LVM_FLOAT Alpha;
289 LVM_FLOAT AlphaTap;
290
291 Alpha = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TC,
292 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
293 1);
294
295 AlphaTap = LVM_Mixer_TimeConstant(LVREV_ALLPASS_TAP_TC,
296 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
297 1);
298
299 for (i = 0; i < 4; i++)
300 {
301 pPrivate->Mixer_APTaps[i].Alpha1 = AlphaTap;
302 pPrivate->Mixer_APTaps[i].Alpha2 = AlphaTap;
303 pPrivate->Mixer_SGFeedback[i].Alpha = Alpha;
304 pPrivate->Mixer_SGFeedforward[i].Alpha = Alpha;
305 }
306 }
307
308 /*
309 * Update the feed back gain
310 */
311 if( (pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
312 (pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
313 (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) ||
314 (pPrivate->bFirstControl == LVM_TRUE))
315 {
316
317 LVM_FLOAT G[4]; /* Feedback gain (Q7.24) */
318
319 if(pPrivate->NewParams.T60 == 0)
320 {
321 G[3] = 0;
322 G[2] = 0;
323 G[1] = 0;
324 G[0] = 0;
325 }
326 else
327 {
328 LVM_FLOAT Temp1;
329 LVM_FLOAT Temp2;
330 LVM_INT16 i;
331 LVM_FLOAT ScaleTable[] = {LVREV_T_3_Power_minus0_on_4, LVREV_T_3_Power_minus1_on_4,
332 LVREV_T_3_Power_minus2_on_4, LVREV_T_3_Power_minus3_on_4};
333
334 /*
335 * For each delay line
336 */
337 for (i = 0; i < NumberOfDelayLines; i++)
338 {
339 Temp1 = (3 * pPrivate->RoomSizeInms * ScaleTable[i]) / pPrivate->NewParams.T60;
340 if(Temp1 >= (4))
341 {
342 G[i] = 0;
343 }
344 else if((Temp1 >= (2)))
345 {
346 Temp2 = LVM_Power10(-(Temp1 / 2.0f));
347 Temp1 = LVM_Power10(-(Temp1 / 2.0f));
348 Temp1 = Temp1 * Temp2;
349 }
350 else
351 {
352 Temp1 = LVM_Power10(-(Temp1));
353 }
354 if (NumberOfDelayLines == 1)
355 {
356 G[i] = Temp1;
357 }
358 else
359 {
360 LVM_FLOAT TempG;
361 TempG = Temp1 * ONE_OVER_SQRT_TWO;
362 G[i]=TempG;
363 }
364 }
365 }
366
367 /* Set up the feedback mixers for four delay lines */
368 pPrivate->FeedbackMixer[0].Target=G[0];
369 pPrivate->FeedbackMixer[1].Target=G[1];
370 pPrivate->FeedbackMixer[2].Target=G[2];
371 pPrivate->FeedbackMixer[3].Target=G[3];
372 }
373
374 /*
375 * Calculate the gain correction
376 */
377 if((pPrivate->NewParams.RoomSize != pPrivate->CurrentParams.RoomSize) ||
378 (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) ||
379 (pPrivate->NewParams.T60 != pPrivate->CurrentParams.T60) )
380 {
381 LVM_INT32 Index=0;
382 LVM_FLOAT Index_FLOAT;
383 LVM_INT32 i=0;
384 LVM_FLOAT Gain=0;
385 LVM_INT32 RoomSize=0;
386 LVM_FLOAT T60;
387 LVM_FLOAT Coefs[5];
388
389 if(pPrivate->NewParams.RoomSize == 0)
390 {
391 RoomSize = 1;
392 }
393 else
394 {
395 RoomSize = (LVM_INT32)pPrivate->NewParams.RoomSize;
396 }
397
398 if(pPrivate->NewParams.T60 < 100)
399 {
400 T60 = 100 * LVREV_T60_SCALE;
401 }
402 else
403 {
404 T60 = pPrivate->NewParams.T60 * LVREV_T60_SCALE;
405 }
406
407 /* Find the nearest room size in table */
408 for(i = 0; i < 24; i++)
409 {
410 if(RoomSize <= LVREV_GainPolyTable[i][0])
411 {
412 Index = i;
413 break;
414 }
415 }
416
417 if(RoomSize == LVREV_GainPolyTable[Index][0])
418 {
419 /* Take table values if the room size is in table */
420 for(i = 1; i < 5; i++)
421 {
422 Coefs[i-1] = LVREV_GainPolyTable[Index][i];
423 }
424 Coefs[4] = 0;
425 Gain = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
426 }
427 else
428 {
429 /* Interpolate the gain between nearest room sizes */
430
431 LVM_FLOAT Gain1,Gain2;
432 LVM_INT32 Tot_Dist,Dist;
433
434 Tot_Dist = (LVM_UINT32)LVREV_GainPolyTable[Index][0] - \
435 (LVM_UINT32)LVREV_GainPolyTable[Index-1][0];
436 Dist = RoomSize - (LVM_UINT32)LVREV_GainPolyTable[Index - 1][0];
437
438 /* Get gain for first */
439 for(i = 1; i < 5; i++)
440 {
441 Coefs[i-1] = LVREV_GainPolyTable[Index-1][i];
442 }
443 Coefs[4] = 0;
444
445 Gain1 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
446
447 /* Get gain for second */
448 for(i = 1; i < 5; i++)
449 {
450 Coefs[i-1] = LVREV_GainPolyTable[Index][i];
451 }
452 Coefs[4] = 0;
453
454 Gain2 = LVM_Polynomial(3, Coefs, T60); /* Q.24 result */
455
456 /* Linear Interpolate the gain */
457 Gain = Gain1 + (((Gain2 - Gain1) * Dist) / (Tot_Dist));
458 }
459
460 /*
461 * Get the inverse of gain: Q.15
462 * Gain is mostly above one except few cases, take only gains above 1
463 */
464 if(Gain < 1)
465 {
466 pPrivate->Gain = 1;
467 }
468 else
469 {
470 pPrivate->Gain = 1 / Gain;
471 }
472
473 Index_FLOAT = 100.0f / (LVM_FLOAT)(100 + pPrivate->NewParams.Level);
474 pPrivate->Gain = pPrivate->Gain * Index_FLOAT;
475 pPrivate->GainMixer.Target = (pPrivate->Gain*Index_FLOAT) / 2;
476 }
477
478 /*
479 * Update the all pass comb filter coefficient
480 */
481 if( (pPrivate->NewParams.Density != pPrivate->CurrentParams.Density) ||
482 (pPrivate->bFirstControl == LVM_TRUE))
483 {
484 LVM_INT16 i;
485 LVM_FLOAT b = (LVM_FLOAT)pPrivate->NewParams.Density * LVREV_B_8_on_1000;
486
487 for (i = 0; i < 4; i++)
488 {
489 pPrivate->Mixer_SGFeedback[i].Target = b;
490 pPrivate->Mixer_SGFeedforward[i].Target = b;
491 }
492 }
493
494 /*
495 * Update the bypass mixer time constant
496 */
497 if((pPrivate->NewParams.SampleRate != pPrivate->CurrentParams.SampleRate) ||
498 (pPrivate->bFirstControl == LVM_TRUE))
499 {
500 LVM_UINT16 NumChannels = 1; /* Assume MONO format */
501 LVM_FLOAT Alpha;
502
503 Alpha = LVM_Mixer_TimeConstant(LVREV_FEEDBACKMIXER_TC,
504 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate),
505 NumChannels);
506 pPrivate->FeedbackMixer[0].Alpha = Alpha;
507 pPrivate->FeedbackMixer[1].Alpha = Alpha;
508 pPrivate->FeedbackMixer[2].Alpha = Alpha;
509 pPrivate->FeedbackMixer[3].Alpha = Alpha;
510
511 NumChannels = 2; /* Always stereo output */
512 pPrivate->BypassMixer.Alpha1 = LVM_Mixer_TimeConstant(LVREV_BYPASSMIXER_TC,
513 LVM_GetFsFromTable(pPrivate->NewParams.SampleRate), NumChannels);
514 pPrivate->BypassMixer.Alpha2 = pPrivate->BypassMixer.Alpha1;
515 pPrivate->GainMixer.Alpha = pPrivate->BypassMixer.Alpha1;
516 }
517
518 /*
519 * Update the bypass mixer targets
520 */
521 if( (pPrivate->NewParams.Level != pPrivate->CurrentParams.Level) &&
522 (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
523 {
524 pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
525 pPrivate->BypassMixer.Target1 = 0x00000000;
526 if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
527 {
528 pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
529 }
530 if (pPrivate->NewParams.Level != 0)
531 {
532 pPrivate->bDisableReverb = LVM_FALSE;
533 }
534 }
535
536 if(pPrivate->NewParams.OperatingMode != pPrivate->CurrentParams.OperatingMode)
537 {
538 if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
539 {
540 pPrivate->BypassMixer.Target2 = (LVM_FLOAT)(pPrivate->NewParams.Level ) / 100.0f;
541 pPrivate->BypassMixer.Target1 = 0x00000000;
542
543 pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
544 OperatingMode = LVM_MODE_ON;
545 if (pPrivate->NewParams.Level == 0)
546 {
547 pPrivate->bDisableReverb = LVM_TRUE;
548 }
549 else
550 {
551 pPrivate->bDisableReverb = LVM_FALSE;
552 }
553 }
554 else if (pPrivate->bFirstControl == LVM_FALSE)
555 {
556 pPrivate->BypassMixer.Target2 = 0x00000000;
557 pPrivate->BypassMixer.Target1 = 0x00000000;
558 pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
559 pPrivate->GainMixer.Target = 0.03125f;
560 OperatingMode = LVM_MODE_ON;
561 }
562 else
563 {
564 OperatingMode = LVM_MODE_OFF;
565 }
566 }
567
568 /* If it is the first call to ApplyNew settings force the current to the target \
569 to begin immediate playback of the effect */
570 if(pPrivate->bFirstControl == LVM_TRUE)
571 {
572 pPrivate->BypassMixer.Current1 = pPrivate->BypassMixer.Target1;
573 pPrivate->BypassMixer.Current2 = pPrivate->BypassMixer.Target2;
574 }
575
576 /*
577 * Copy the new parameters
578 */
579 pPrivate->CurrentParams = pPrivate->NewParams;
580 pPrivate->CurrentParams.OperatingMode = OperatingMode;
581
582 /*
583 * Update flag
584 */
585 if(pPrivate->bFirstControl == LVM_TRUE)
586 {
587 pPrivate->bFirstControl = LVM_FALSE;
588 }
589
590 return LVREV_SUCCESS;
591 }
592 /****************************************************************************************/
593 /* */
594 /* FUNCTION: BypassMixer_Callback */
595 /* */
596 /* DESCRIPTION: */
597 /* Controls the On to Off operating mode transition */
598 /* */
599 /* PARAMETERS: */
600 /* pPrivate Pointer to the instance private parameters */
601 /* */
602 /* RETURNS: */
603 /* LVREV_Success Succeeded */
604 /* LVREV_NULLADDRESS When pPrivate is NULL */
605 /* */
606 /* NOTES: */
607 /* */
608 /****************************************************************************************/
BypassMixer_Callback(void * pCallbackData,void * pGeneralPurpose,LVM_INT16 GeneralPurpose)609 LVM_INT32 BypassMixer_Callback (void *pCallbackData,
610 void *pGeneralPurpose,
611 LVM_INT16 GeneralPurpose )
612 {
613
614 LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)pCallbackData;
615
616 /*
617 * Avoid build warnings
618 */
619 (void)pGeneralPurpose;
620 (void)GeneralPurpose;
621
622 /*
623 * Turn off
624 */
625 pLVREV_Private->CurrentParams.OperatingMode = LVM_MODE_OFF;
626 pLVREV_Private->bDisableReverb = LVM_TRUE;
627 LVREV_ClearAudioBuffers((LVREV_Handle_t)pCallbackData);
628
629 return 0;
630 }
631
632 /* End of file */
633
634