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