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