1/*---------------------------------------------------------------------------- 2 * 3 * File: 4 * eas_wtengine.c 5 * 6 * Contents and purpose: 7 * This file contains the critical synthesizer components that need to 8 * be optimized for best performance. 9 * 10 * Copyright Sonic Network Inc. 2004-2005 11 12 * Licensed under the Apache License, Version 2.0 (the "License"); 13 * you may not use this file except in compliance with the License. 14 * You may obtain a copy of the License at 15 * 16 * http://www.apache.org/licenses/LICENSE-2.0 17 * 18 * Unless required by applicable law or agreed to in writing, software 19 * distributed under the License is distributed on an "AS IS" BASIS, 20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 * See the License for the specific language governing permissions and 22 * limitations under the License. 23 * 24 *---------------------------------------------------------------------------- 25 * Revision Control: 26 * $Revision: 844 $ 27 * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ 28 *---------------------------------------------------------------------------- 29*/ 30 31/*------------------------------------ 32 * includes 33 *------------------------------------ 34*/ 35#include "log/log.h" 36#include <cutils/log.h> 37 38#include "eas_types.h" 39#include "eas_math.h" 40#include "eas_audioconst.h" 41#include "eas_sndlib.h" 42#include "eas_wtengine.h" 43#include "eas_mixer.h" 44 45/*---------------------------------------------------------------------------- 46 * prototypes 47 *---------------------------------------------------------------------------- 48*/ 49extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); 50extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); 51 52#if defined(_OPTIMIZED_MONO) 53extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); 54#else 55extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); 56extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); 57#endif 58 59#if defined(_FILTER_ENABLED) 60extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); 61#endif 62 63#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) 64/*---------------------------------------------------------------------------- 65 * WT_VoiceGain 66 *---------------------------------------------------------------------------- 67 * Purpose: 68 * Output gain for individual voice 69 * 70 * Inputs: 71 * 72 * Outputs: 73 * 74 *---------------------------------------------------------------------------- 75*/ 76/*lint -esym(715, pWTVoice) reserved for future use */ 77void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 78{ 79 EAS_I32 *pMixBuffer; 80 EAS_PCM *pInputBuffer; 81 EAS_I32 gain; 82 EAS_I32 gainIncrement; 83 EAS_I32 tmp0; 84 EAS_I32 tmp1; 85 EAS_I32 tmp2; 86 EAS_I32 numSamples; 87 88#if (NUM_OUTPUT_CHANNELS == 2) 89 EAS_I32 gainLeft, gainRight; 90#endif 91 92 /* initialize some local variables */ 93 numSamples = pWTIntFrame->numSamples; 94 if (numSamples <= 0) { 95 ALOGE("b/26366256"); 96 android_errorWriteLog(0x534e4554, "26366256"); 97 return; 98 } 99 pMixBuffer = pWTIntFrame->pMixBuffer; 100 pInputBuffer = pWTIntFrame->pAudioBuffer; 101 102 /*lint -e{703} <avoid multiply for performance>*/ 103 gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); 104 if (gainIncrement < 0) 105 gainIncrement++; 106 /*lint -e{703} <avoid multiply for performance>*/ 107 gain = pWTIntFrame->prevGain << 16; 108 109#if (NUM_OUTPUT_CHANNELS == 2) 110 gainLeft = pWTVoice->gainLeft; 111 gainRight = pWTVoice->gainRight; 112#endif 113 114 while (numSamples--) { 115 116 /* incremental gain step to prevent zipper noise */ 117 tmp0 = *pInputBuffer++; 118 gain += gainIncrement; 119 /*lint -e{704} <avoid divide>*/ 120 tmp2 = gain >> 16; 121 122 /* scale sample by gain */ 123 tmp2 *= tmp0; 124 125 126 /* stereo output */ 127#if (NUM_OUTPUT_CHANNELS == 2) 128 /*lint -e{704} <avoid divide>*/ 129 tmp2 = tmp2 >> 14; 130 131 /* get the current sample in the final mix buffer */ 132 tmp1 = *pMixBuffer; 133 134 /* left channel */ 135 tmp0 = tmp2 * gainLeft; 136 /*lint -e{704} <avoid divide>*/ 137 tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; 138 tmp1 += tmp0; 139 *pMixBuffer++ = tmp1; 140 141 /* get the current sample in the final mix buffer */ 142 tmp1 = *pMixBuffer; 143 144 /* right channel */ 145 tmp0 = tmp2 * gainRight; 146 /*lint -e{704} <avoid divide>*/ 147 tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; 148 tmp1 += tmp0; 149 *pMixBuffer++ = tmp1; 150 151 /* mono output */ 152#else 153 154 /* get the current sample in the final mix buffer */ 155 tmp1 = *pMixBuffer; 156 /*lint -e{704} <avoid divide>*/ 157 tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); 158 tmp1 += tmp2; 159 *pMixBuffer++ = tmp1; 160#endif 161 162 } 163} 164#endif 165 166#ifndef NATIVE_EAS_KERNEL 167/*---------------------------------------------------------------------------- 168 * WT_Interpolate 169 *---------------------------------------------------------------------------- 170 * Purpose: 171 * Interpolation engine for wavetable synth 172 * 173 * Inputs: 174 * 175 * Outputs: 176 * 177 *---------------------------------------------------------------------------- 178*/ 179void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 180{ 181 EAS_PCM *pOutputBuffer; 182 EAS_I32 phaseInc; 183 EAS_I32 phaseFrac; 184 EAS_I32 acc0; 185 const EAS_SAMPLE *pSamples; 186 const EAS_SAMPLE *loopEnd; 187 EAS_I32 samp1; 188 EAS_I32 samp2; 189 EAS_I32 numSamples; 190 191 /* initialize some local variables */ 192 numSamples = pWTIntFrame->numSamples; 193 if (numSamples <= 0) { 194 ALOGE("b/26366256"); 195 android_errorWriteLog(0x534e4554, "26366256"); 196 return; 197 } 198 pOutputBuffer = pWTIntFrame->pAudioBuffer; 199 200 loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; 201 pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; 202 /*lint -e{713} truncation is OK */ 203 phaseFrac = pWTVoice->phaseFrac; 204 phaseInc = pWTIntFrame->frame.phaseIncrement; 205 206 /* fetch adjacent samples */ 207#if defined(_8_BIT_SAMPLES) 208 /*lint -e{701} <avoid multiply for performance>*/ 209 samp1 = pSamples[0] << 8; 210 /*lint -e{701} <avoid multiply for performance>*/ 211 samp2 = pSamples[1] << 8; 212#else 213 samp1 = pSamples[0]; 214 samp2 = pSamples[1]; 215#endif 216 217 while (numSamples--) { 218 219 /* linear interpolation */ 220 acc0 = samp2 - samp1; 221 acc0 = acc0 * phaseFrac; 222 /*lint -e{704} <avoid divide>*/ 223 acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); 224 225 /* save new output sample in buffer */ 226 /*lint -e{704} <avoid divide>*/ 227 *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); 228 229 /* increment phase */ 230 phaseFrac += phaseInc; 231 /*lint -e{704} <avoid divide>*/ 232 acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; 233 234 /* next sample */ 235 if (acc0 > 0) { 236 237 /* advance sample pointer */ 238 pSamples += acc0; 239 phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); 240 241 /* check for loop end */ 242 acc0 = (EAS_I32) (pSamples - loopEnd); 243 if (acc0 >= 0) 244 pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; 245 246 /* fetch new samples */ 247#if defined(_8_BIT_SAMPLES) 248 /*lint -e{701} <avoid multiply for performance>*/ 249 samp1 = pSamples[0] << 8; 250 /*lint -e{701} <avoid multiply for performance>*/ 251 samp2 = pSamples[1] << 8; 252#else 253 samp1 = pSamples[0]; 254 samp2 = pSamples[1]; 255#endif 256 } 257 } 258 259 /* save pointer and phase */ 260 pWTVoice->phaseAccum = (EAS_U32) pSamples; 261 pWTVoice->phaseFrac = (EAS_U32) phaseFrac; 262} 263#endif 264 265#ifndef NATIVE_EAS_KERNEL 266/*---------------------------------------------------------------------------- 267 * WT_InterpolateNoLoop 268 *---------------------------------------------------------------------------- 269 * Purpose: 270 * Interpolation engine for wavetable synth 271 * 272 * Inputs: 273 * 274 * Outputs: 275 * 276 *---------------------------------------------------------------------------- 277*/ 278void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 279{ 280 EAS_PCM *pOutputBuffer; 281 EAS_I32 phaseInc; 282 EAS_I32 phaseFrac; 283 EAS_I32 acc0; 284 const EAS_SAMPLE *pSamples; 285 EAS_I32 samp1; 286 EAS_I32 samp2; 287 EAS_I32 numSamples; 288 289 /* initialize some local variables */ 290 numSamples = pWTIntFrame->numSamples; 291 if (numSamples <= 0) { 292 ALOGE("b/26366256"); 293 android_errorWriteLog(0x534e4554, "26366256"); 294 return; 295 } 296 pOutputBuffer = pWTIntFrame->pAudioBuffer; 297 298 phaseInc = pWTIntFrame->frame.phaseIncrement; 299 pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; 300 phaseFrac = (EAS_I32)pWTVoice->phaseFrac; 301 302 /* fetch adjacent samples */ 303#if defined(_8_BIT_SAMPLES) 304 /*lint -e{701} <avoid multiply for performance>*/ 305 samp1 = pSamples[0] << 8; 306 /*lint -e{701} <avoid multiply for performance>*/ 307 samp2 = pSamples[1] << 8; 308#else 309 samp1 = pSamples[0]; 310 samp2 = pSamples[1]; 311#endif 312 313 while (numSamples--) { 314 315 316 /* linear interpolation */ 317 acc0 = samp2 - samp1; 318 acc0 = acc0 * phaseFrac; 319 /*lint -e{704} <avoid divide>*/ 320 acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); 321 322 /* save new output sample in buffer */ 323 /*lint -e{704} <avoid divide>*/ 324 *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); 325 326 /* increment phase */ 327 phaseFrac += phaseInc; 328 /*lint -e{704} <avoid divide>*/ 329 acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; 330 331 /* next sample */ 332 if (acc0 > 0) { 333 334 /* advance sample pointer */ 335 pSamples += acc0; 336 phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); 337 338 /* fetch new samples */ 339#if defined(_8_BIT_SAMPLES) 340 /*lint -e{701} <avoid multiply for performance>*/ 341 samp1 = pSamples[0] << 8; 342 /*lint -e{701} <avoid multiply for performance>*/ 343 samp2 = pSamples[1] << 8; 344#else 345 samp1 = pSamples[0]; 346 samp2 = pSamples[1]; 347#endif 348 } 349 } 350 351 /* save pointer and phase */ 352 pWTVoice->phaseAccum = (EAS_U32) pSamples; 353 pWTVoice->phaseFrac = (EAS_U32) phaseFrac; 354} 355#endif 356 357#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) 358/*---------------------------------------------------------------------------- 359 * WT_VoiceFilter 360 *---------------------------------------------------------------------------- 361 * Purpose: 362 * Implements a 2-pole filter 363 * 364 * Inputs: 365 * 366 * Outputs: 367 * 368 *---------------------------------------------------------------------------- 369*/ 370void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) 371{ 372 EAS_PCM *pAudioBuffer; 373 EAS_I32 k; 374 EAS_I32 b1; 375 EAS_I32 b2; 376 EAS_I32 z1; 377 EAS_I32 z2; 378 EAS_I32 acc0; 379 EAS_I32 acc1; 380 EAS_I32 numSamples; 381 382 /* initialize some local variables */ 383 numSamples = pWTIntFrame->numSamples; 384 if (numSamples <= 0) { 385 ALOGE("b/26366256"); 386 android_errorWriteLog(0x534e4554, "26366256"); 387 return; 388 } 389 pAudioBuffer = pWTIntFrame->pAudioBuffer; 390 391 z1 = pFilter->z1; 392 z2 = pFilter->z2; 393 b1 = -pWTIntFrame->frame.b1; 394 395 /*lint -e{702} <avoid divide> */ 396 b2 = -pWTIntFrame->frame.b2 >> 1; 397 398 /*lint -e{702} <avoid divide> */ 399 k = pWTIntFrame->frame.k >> 1; 400 401 while (numSamples--) 402 { 403 404 /* do filter calculations */ 405 acc0 = *pAudioBuffer; 406 acc1 = z1 * b1; 407 acc1 += z2 * b2; 408 acc0 = acc1 + k * acc0; 409 z2 = z1; 410 411 /*lint -e{702} <avoid divide> */ 412 z1 = acc0 >> 14; 413 *pAudioBuffer++ = (EAS_I16) z1; 414 } 415 416 /* save delay values */ 417 pFilter->z1 = (EAS_I16) z1; 418 pFilter->z2 = (EAS_I16) z2; 419} 420#endif 421 422/*---------------------------------------------------------------------------- 423 * WT_NoiseGenerator 424 *---------------------------------------------------------------------------- 425 * Purpose: 426 * Generate pseudo-white noise using PRNG and interpolation engine 427 * 428 * Inputs: 429 * 430 * Outputs: 431 * 432 * Notes: 433 * This output is scaled -12dB to prevent saturation in the filter. For a 434 * high quality synthesizer, the output can be set to full scale, however 435 * if the filter is used, it can overflow with certain coefficients. In this 436 * case, either a saturation operation should take in the filter before 437 * scaling back to 16 bits or the signal path should be increased to 18 bits 438 * or more. 439 *---------------------------------------------------------------------------- 440*/ 441 void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 442 { 443 EAS_PCM *pOutputBuffer; 444 EAS_I32 phaseInc; 445 EAS_I32 tmp0; 446 EAS_I32 tmp1; 447 EAS_I32 nInterpolatedSample; 448 EAS_I32 numSamples; 449 450 /* initialize some local variables */ 451 numSamples = pWTIntFrame->numSamples; 452 if (numSamples <= 0) { 453 ALOGE("b/26366256"); 454 android_errorWriteLog(0x534e4554, "26366256"); 455 return; 456 } 457 pOutputBuffer = pWTIntFrame->pAudioBuffer; 458 phaseInc = pWTIntFrame->frame.phaseIncrement; 459 460 /* get last two samples generated */ 461 /*lint -e{704} <avoid divide for performance>*/ 462 tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; 463 /*lint -e{704} <avoid divide for performance>*/ 464 tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; 465 466 /* generate a buffer of noise */ 467 while (numSamples--) { 468 nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); 469 nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); 470 *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; 471 472 /* update PRNG */ 473 pWTVoice->phaseFrac += (EAS_U32) phaseInc; 474 if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { 475 tmp0 = tmp1; 476 pWTVoice->phaseAccum = pWTVoice->loopEnd; 477 pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); 478 tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; 479 pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); 480 } 481 482 } 483} 484 485#ifndef _OPTIMIZED_MONO 486/*---------------------------------------------------------------------------- 487 * WT_ProcessVoice 488 *---------------------------------------------------------------------------- 489 * Purpose: 490 * This routine does the block processing for one voice. It is isolated 491 * from the main synth code to allow for various implementation-specific 492 * optimizations. It calls the interpolator, filter, and gain routines 493 * appropriate for a particular configuration. 494 * 495 * Inputs: 496 * 497 * Outputs: 498 * 499 * Notes: 500 *---------------------------------------------------------------------------- 501*/ 502void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 503{ 504 505 /* use noise generator */ 506 if (pWTVoice->loopStart == WT_NOISE_GENERATOR) 507 WT_NoiseGenerator(pWTVoice, pWTIntFrame); 508 509 /* generate interpolated samples for looped waves */ 510 else if (pWTVoice->loopStart != pWTVoice->loopEnd) 511 WT_Interpolate(pWTVoice, pWTIntFrame); 512 513 /* generate interpolated samples for unlooped waves */ 514 else 515 { 516 WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); 517 } 518 519#ifdef _FILTER_ENABLED 520 if (pWTIntFrame->frame.k != 0) 521 WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); 522#endif 523 524//2 TEST NEW MIXER FUNCTION 525#ifdef UNIFIED_MIXER 526 { 527 EAS_I32 gainLeft, gainIncLeft; 528 529#if (NUM_OUTPUT_CHANNELS == 2) 530 EAS_I32 gainRight, gainIncRight; 531#endif 532 533 gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; 534 gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; 535 536#if (NUM_OUTPUT_CHANNELS == 2) 537 gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; 538 gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; 539 EAS_MixStream( 540 pWTIntFrame->pAudioBuffer, 541 pWTIntFrame->pMixBuffer, 542 pWTIntFrame->numSamples, 543 gainLeft, 544 gainRight, 545 gainIncLeft, 546 gainIncRight, 547 MIX_FLAGS_STEREO_OUTPUT); 548 549#else 550 EAS_MixStream( 551 pWTIntFrame->pAudioBuffer, 552 pWTIntFrame->pMixBuffer, 553 pWTIntFrame->numSamples, 554 gainLeft, 555 0, 556 gainIncLeft, 557 0, 558 0); 559#endif 560 } 561 562#else 563 /* apply gain, and left and right gain */ 564 WT_VoiceGain(pWTVoice, pWTIntFrame); 565#endif 566} 567#endif 568 569#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) 570/*---------------------------------------------------------------------------- 571 * WT_InterpolateMono 572 *---------------------------------------------------------------------------- 573 * Purpose: 574 * A C version of the sample interpolation + gain routine, optimized for mono. 575 * It's not pretty, but it matches the assembly code exactly. 576 * 577 * Inputs: 578 * 579 * Outputs: 580 * 581 * Notes: 582 *---------------------------------------------------------------------------- 583*/ 584void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 585{ 586 EAS_I32 *pMixBuffer; 587 const EAS_I8 *pLoopEnd; 588 const EAS_I8 *pCurrentPhaseInt; 589 EAS_I32 numSamples; 590 EAS_I32 gain; 591 EAS_I32 gainIncrement; 592 EAS_I32 currentPhaseFrac; 593 EAS_I32 phaseInc; 594 EAS_I32 tmp0; 595 EAS_I32 tmp1; 596 EAS_I32 tmp2; 597 EAS_I8 *pLoopStart; 598 599 numSamples = pWTIntFrame->numSamples; 600 if (numSamples <= 0) { 601 ALOGE("b/26366256"); 602 android_errorWriteLog(0x534e4554, "26366256"); 603 return; 604 } 605 pMixBuffer = pWTIntFrame->pMixBuffer; 606 607 /* calculate gain increment */ 608 gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); 609 if (gainIncrement < 0) 610 gainIncrement++; 611 gain = pWTIntFrame->prevGain << 16; 612 613 pCurrentPhaseInt = pWTVoice->pPhaseAccum; 614 currentPhaseFrac = pWTVoice->phaseFrac; 615 phaseInc = pWTIntFrame->phaseIncrement; 616 617 pLoopStart = pWTVoice->pLoopStart; 618 pLoopEnd = pWTVoice->pLoopEnd + 1; 619 620InterpolationLoop: 621 tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); 622 if (tmp0 >= 0) 623 pCurrentPhaseInt = pLoopStart + tmp0; 624 625 tmp0 = *pCurrentPhaseInt; 626 tmp1 = *(pCurrentPhaseInt + 1); 627 628 tmp2 = phaseInc + currentPhaseFrac; 629 630 tmp1 = tmp1 - tmp0; 631 tmp1 = tmp1 * currentPhaseFrac; 632 633 tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); 634 635 pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); 636 currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; 637 638 gain += gainIncrement; 639 tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); 640 641 tmp0 = *pMixBuffer; 642 tmp2 = tmp1 * tmp2; 643 tmp2 = (tmp2 >> 9); 644 tmp0 = tmp2 + tmp0; 645 *pMixBuffer++ = tmp0; 646 647 numSamples--; 648 if (numSamples > 0) 649 goto InterpolationLoop; 650 651 pWTVoice->pPhaseAccum = pCurrentPhaseInt; 652 pWTVoice->phaseFrac = currentPhaseFrac; 653 /*lint -e{702} <avoid divide>*/ 654 pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); 655} 656#endif 657 658#ifdef _OPTIMIZED_MONO 659/*---------------------------------------------------------------------------- 660 * WT_ProcessVoice 661 *---------------------------------------------------------------------------- 662 * Purpose: 663 * This routine does the block processing for one voice. It is isolated 664 * from the main synth code to allow for various implementation-specific 665 * optimizations. It calls the interpolator, filter, and gain routines 666 * appropriate for a particular configuration. 667 * 668 * Inputs: 669 * 670 * Outputs: 671 * 672 * Notes: 673 * This special version works handles an optimized mono-only signal 674 * without filters 675 *---------------------------------------------------------------------------- 676*/ 677void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) 678{ 679 680 /* use noise generator */ 681 if (pWTVoice->loopStart== WT_NOISE_GENERATOR) 682 { 683 WT_NoiseGenerator(pWTVoice, pWTIntFrame); 684 WT_VoiceGain(pWTVoice, pWTIntFrame); 685 } 686 687 /* or generate interpolated samples */ 688 else 689 { 690 WT_InterpolateMono(pWTVoice, pWTIntFrame); 691 } 692} 693#endif 694 695