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 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 /****************************************************************************************/ 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