1 /*----------------------------------------------------------------------------
2  *
3  * File:
4  * eas_mixer.c
5  *
6  * Contents and purpose:
7  * This file contains the critical components of the mix engine that
8  * must be optimized for best performance.
9  *
10  * Copyright Sonic Network Inc. 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: 706 $
27  *   $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $
28  *----------------------------------------------------------------------------
29 */
30 
31 //3 dls: This module is in the midst of being converted from a synth
32 //3 specific module to a general purpose mix engine
33 
34 /*------------------------------------
35  * includes
36  *------------------------------------
37 */
38 #include "eas_data.h"
39 #include "eas_host.h"
40 #include "eas_math.h"
41 #include "eas_mixer.h"
42 #include "eas_config.h"
43 #include "eas_report.h"
44 
45 #ifdef _MAXIMIZER_ENABLED
46 EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples);
47 #endif
48 
49 /*------------------------------------
50  * defines
51  *------------------------------------
52 */
53 
54 /* need to boost stereo by ~3dB to compensate for the panner */
55 #define STEREO_3DB_GAIN_BOOST       512
56 
57 /*----------------------------------------------------------------------------
58  * EAS_MixEngineInit()
59  *----------------------------------------------------------------------------
60  * Purpose:
61  * Prepares the mix engine for work, allocates buffers, locates effects modules, etc.
62  *
63  * Inputs:
64  * pEASData         - instance data
65  * pInstData        - pointer to variable to receive instance data handle
66  *
67  * Outputs:
68  *
69  * Side Effects:
70  *
71  *----------------------------------------------------------------------------
72 */
EAS_MixEngineInit(S_EAS_DATA * pEASData)73 EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData)
74 {
75 
76     /* check Configuration Module for mix buffer allocation */
77     if (pEASData->staticMemoryModel)
78         pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER);
79     else
80         pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
81     if (pEASData->pMixBuffer == NULL)
82     {
83         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ }
84         return EAS_ERROR_MALLOC_FAILED;
85     }
86     EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
87 
88     return EAS_SUCCESS;
89 }
90 
91 /*----------------------------------------------------------------------------
92  * EAS_MixEnginePrep()
93  *----------------------------------------------------------------------------
94  * Purpose:
95  * Performs prep before synthesize a buffer of audio, such as clearing
96  * audio buffers, etc.
97  *
98  * Inputs:
99  * psEASData - pointer to overall EAS data structure
100  *
101  * Outputs:
102  *
103  * Side Effects:
104  *
105  *----------------------------------------------------------------------------
106 */
EAS_MixEnginePrep(S_EAS_DATA * pEASData,EAS_I32 numSamples)107 void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples)
108 {
109 
110     /* clear the mix buffer */
111 #if (NUM_OUTPUT_CHANNELS == 2)
112     EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2);
113 #else
114     EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long));
115 #endif
116 
117     /* need to clear other side-chain effect buffers (chorus & reverb) */
118 }
119 
120 /*----------------------------------------------------------------------------
121  * EAS_MixEnginePost
122  *----------------------------------------------------------------------------
123  * Purpose:
124  * This routine does the post-processing after all voices have been
125  * synthesized. It calls any sweeteners and does the final mixdown to
126  * the output buffer.
127  *
128  * Inputs:
129  *
130  * Outputs:
131  *
132  * Notes:
133  *----------------------------------------------------------------------------
134 */
EAS_MixEnginePost(S_EAS_DATA * pEASData,EAS_I32 numSamples)135 void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples)
136 {
137     EAS_U16 gain;
138 
139 //3 dls: Need to restore the mix engine metrics
140 
141     /* calculate the gain multiplier */
142 #ifdef _MAXIMIZER_ENABLED
143     if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect)
144     {
145         EAS_I32 temp;
146         temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples);
147         temp = (temp * pEASData->masterGain) >> 15;
148         if (temp > 32767)
149             gain = 32767;
150         else
151             gain = (EAS_U16) temp;
152     }
153     else
154         gain = (EAS_U16) pEASData->masterGain;
155 #else
156     gain = (EAS_U16) pEASData->masterGain;
157 #endif
158 
159     /* Not using all the gain bits for now
160      * Reduce the input to the compressor by 6dB to prevent saturation
161      */
162 #ifdef _COMPRESSOR_ENABLED
163     if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
164         gain = gain >> 5;
165     else
166         gain = gain >> 4;
167 #else
168     gain = gain >> 4;
169 #endif
170 
171     /* convert 32-bit mix buffer to 16-bit output format */
172 #if (NUM_OUTPUT_CHANNELS == 2)
173     SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2));
174 #else
175     SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples);
176 #endif
177 
178 #ifdef _ENHANCER_ENABLED
179     /* enhancer effect */
180     if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData)
181         (*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess)
182             (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData,
183             pEASData->pOutputAudioBuffer,
184             pEASData->pOutputAudioBuffer,
185             numSamples);
186 #endif
187 
188 #ifdef _GRAPHIC_EQ_ENABLED
189     /* graphic EQ effect */
190     if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData)
191         (*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess)
192             (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData,
193             pEASData->pOutputAudioBuffer,
194             pEASData->pOutputAudioBuffer,
195             numSamples);
196 #endif
197 
198 #ifdef _COMPRESSOR_ENABLED
199     /* compressor effect */
200     if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
201         (*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess)
202             (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData,
203             pEASData->pOutputAudioBuffer,
204             pEASData->pOutputAudioBuffer,
205             numSamples);
206 #endif
207 
208 #ifdef _WOW_ENABLED
209     /* WOW requires a 32-bit buffer, borrow the mix buffer and
210      * pass it as the destination buffer
211      */
212     /*lint -e{740} temporarily passing a parameter through an existing I/F */
213     if (pEASData->effectsModules[EAS_MODULE_WOW].effectData)
214         (*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess)
215             (pEASData->effectsModules[EAS_MODULE_WOW].effectData,
216             pEASData->pOutputAudioBuffer,
217             (EAS_PCM*) pEASData->pMixBuffer,
218             numSamples);
219 #endif
220 
221 #ifdef _TONECONTROLEQ_ENABLED
222     /* ToneControlEQ effect */
223     if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData)
224         (*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess)
225             (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData,
226             pEASData->pOutputAudioBuffer,
227             pEASData->pOutputAudioBuffer,
228             numSamples);
229 #endif
230 
231 #ifdef _REVERB_ENABLED
232     /* Reverb effect */
233     if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData)
234         (*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess)
235             (pEASData->effectsModules[EAS_MODULE_REVERB].effectData,
236             pEASData->pOutputAudioBuffer,
237             pEASData->pOutputAudioBuffer,
238             numSamples);
239 #endif
240 
241 #ifdef _CHORUS_ENABLED
242     /* Chorus effect */
243     if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData)
244         (*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess)
245             (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData,
246             pEASData->pOutputAudioBuffer,
247             pEASData->pOutputAudioBuffer,
248             numSamples);
249 #endif
250 
251 }
252 
253 #ifndef NATIVE_EAS_KERNEL
254 /*----------------------------------------------------------------------------
255  * SynthMasterGain
256  *----------------------------------------------------------------------------
257  * Purpose:
258  * Mixes down audio from 32-bit to 16-bit target buffer
259  *
260  * Inputs:
261  *
262  * Outputs:
263  *
264  *----------------------------------------------------------------------------
265 */
SynthMasterGain(long * pInputBuffer,EAS_PCM * pOutputBuffer,EAS_U16 nGain,EAS_U16 numSamples)266 void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) {
267 
268     /* loop through the buffer */
269     while (numSamples--) {
270         long s;
271 
272         /* read a sample from the input buffer and add some guard bits */
273         s = *pInputBuffer++;
274 
275         /* add some guard bits */
276         /*lint -e{704} <avoid divide for performance>*/
277         s = s >> 7;
278 
279         /* apply master gain */
280         s *= (long) nGain;
281 
282         /* shift to lower 16-bits */
283         /*lint -e{704} <avoid divide for performance>*/
284         s = s >> 9;
285 
286         /* saturate */
287         s = SATURATE(s);
288 
289         *pOutputBuffer++ = (EAS_PCM)s;
290     }
291 }
292 #endif
293 
294 /*----------------------------------------------------------------------------
295  * EAS_MixEngineShutdown()
296  *----------------------------------------------------------------------------
297  * Purpose:
298  * Shuts down effects modules and deallocates memory
299  *
300  * Inputs:
301  * pEASData         - instance data
302  * pInstData        - instance data handle
303  *
304  * Outputs:
305  *
306  * Side Effects:
307  *
308  *----------------------------------------------------------------------------
309 */
EAS_MixEngineShutdown(S_EAS_DATA * pEASData)310 EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData)
311 {
312 
313     /* check Configuration Module for static memory allocation */
314     if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL))
315         EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer);
316 
317     return EAS_SUCCESS;
318 }
319 
320 #ifdef UNIFIED_MIXER
321 #ifndef NATIVE_MIX_STREAM
322 /*----------------------------------------------------------------------------
323  * EAS_MixStream
324  *----------------------------------------------------------------------------
325  * Mix a 16-bit stream into a 32-bit buffer
326  *
327  * pInputBuffer 16-bit input buffer
328  * pMixBuffer   32-bit mix buffer
329  * numSamples   number of samples to mix
330  * gainLeft     initial gain left or mono
331  * gainRight    initial gain right
332  * gainLeft     left gain increment per sample
333  * gainRight    right gain increment per sample
334  * flags        bit 0 = stereo source
335  *              bit 1 = stereo output
336  *----------------------------------------------------------------------------
337 */
EAS_MixStream(EAS_PCM * pInputBuffer,EAS_I32 * pMixBuffer,EAS_I32 numSamples,EAS_I32 gainLeft,EAS_I32 gainRight,EAS_I32 gainIncLeft,EAS_I32 gainIncRight,EAS_I32 flags)338 void EAS_MixStream (EAS_PCM *pInputBuffer, EAS_I32 *pMixBuffer, EAS_I32 numSamples, EAS_I32 gainLeft, EAS_I32 gainRight, EAS_I32 gainIncLeft, EAS_I32 gainIncRight, EAS_I32 flags)
339 {
340     EAS_I32 temp;
341     EAS_INT src, dest;
342 
343     /* NOTE: There are a lot of optimizations that can be done
344      * in the native implementations based on register
345      * availability, etc. For example, it may make sense to
346      * break this down into 8 separate routines:
347      *
348      * 1. Mono source to mono output
349      * 2. Mono source to stereo output
350      * 3. Stereo source to mono output
351      * 4. Stereo source to stereo output
352      * 5. Mono source to mono output - no gain change
353      * 6. Mono source to stereo output - no gain change
354      * 7. Stereo source to mono output - no gain change
355      * 8. Stereo source to stereo output - no gain change
356      *
357      * Other possibilities include loop unrolling, skipping
358      * a gain calculation every 2 or 4 samples, etc.
359      */
360 
361     /* no gain change, use fast loops */
362     if ((gainIncLeft == 0) && (gainIncRight == 0))
363     {
364         switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
365         {
366             /* mono to mono */
367             case 0:
368                 gainLeft >>= 15;
369                 for (src = dest = 0; src < numSamples; src++, dest++)
370                 {
371 
372                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
373                 }
374                 break;
375 
376             /* mono to stereo */
377             case MIX_FLAGS_STEREO_OUTPUT:
378                 gainLeft >>= 15;
379                 gainRight >>= 15;
380                 for (src = dest = 0; src < numSamples; src++, dest+=2)
381                 {
382                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
383                     pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS;
384                 }
385                 break;
386 
387             /* stereo to mono */
388             case MIX_FLAGS_STEREO_SOURCE:
389                 gainLeft >>= 15;
390                 gainRight >>= 15;
391                 for (src = dest = 0; src < numSamples; src+=2, dest++)
392                 {
393                     temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
394                     temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS);
395                     pMixBuffer[dest] += temp;
396                 }
397                 break;
398 
399             /* stereo to stereo */
400             case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
401                 gainLeft >>= 15;
402                 gainRight >>= 15;
403                 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
404                 {
405                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
406                     pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS;
407                 }
408                 break;
409         }
410     }
411 
412     /* gain change - do gain increment */
413     else
414     {
415         switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
416         {
417             /* mono to mono */
418             case 0:
419                 for (src = dest = 0; src < numSamples; src++, dest++)
420                 {
421                     gainLeft += gainIncLeft;
422                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
423                 }
424                 break;
425 
426             /* mono to stereo */
427             case MIX_FLAGS_STEREO_OUTPUT:
428                 for (src = dest = 0; src < numSamples; src++, dest+=2)
429                 {
430                     gainLeft += gainIncLeft;
431                     gainRight += gainIncRight;
432                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
433                     pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
434                 }
435                 break;
436 
437             /* stereo to mono */
438             case MIX_FLAGS_STEREO_SOURCE:
439                 for (src = dest = 0; src < numSamples; src+=2, dest++)
440                 {
441                     gainLeft += gainIncLeft;
442                     gainRight += gainIncRight;
443                     temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
444                     temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS);
445                     pMixBuffer[dest] += temp;
446                 }
447                 break;
448 
449             /* stereo to stereo */
450             case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
451                 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
452                 {
453                     gainLeft += gainIncLeft;
454                     gainRight += gainIncRight;
455                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
456                     pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
457                 }
458                 break;
459         }
460     }
461 }
462 #endif
463 #endif
464 
465