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