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