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