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