• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         numSamples--;
273         /* read a sample from the input buffer and add some guard bits */
274         s = *pInputBuffer++;
275 
276         /* add some guard bits */
277         /*lint -e{704} <avoid divide for performance>*/
278         s = s >> 7;
279 
280         /* apply master gain */
281         s *= (long) nGain;
282 
283         /* shift to lower 16-bits */
284         /*lint -e{704} <avoid divide for performance>*/
285         s = s >> 9;
286 
287         /* saturate */
288         s = SATURATE(s);
289 
290         *pOutputBuffer++ = (EAS_PCM)s;
291     }
292 }
293 #endif
294 
295 /*----------------------------------------------------------------------------
296  * EAS_MixEngineShutdown()
297  *----------------------------------------------------------------------------
298  * Purpose:
299  * Shuts down effects modules and deallocates memory
300  *
301  * Inputs:
302  * pEASData         - instance data
303  * pInstData        - instance data handle
304  *
305  * Outputs:
306  *
307  * Side Effects:
308  *
309  *----------------------------------------------------------------------------
310 */
EAS_MixEngineShutdown(S_EAS_DATA * pEASData)311 EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData)
312 {
313 
314     /* check Configuration Module for static memory allocation */
315     if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL))
316         EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer);
317 
318     return EAS_SUCCESS;
319 }
320 
321 #ifdef UNIFIED_MIXER
322 #ifndef NATIVE_MIX_STREAM
323 /*----------------------------------------------------------------------------
324  * EAS_MixStream
325  *----------------------------------------------------------------------------
326  * Mix a 16-bit stream into a 32-bit buffer
327  *
328  * pInputBuffer 16-bit input buffer
329  * pMixBuffer   32-bit mix buffer
330  * numSamples   number of samples to mix
331  * gainLeft     initial gain left or mono
332  * gainRight    initial gain right
333  * gainLeft     left gain increment per sample
334  * gainRight    right gain increment per sample
335  * flags        bit 0 = stereo source
336  *              bit 1 = stereo output
337  *----------------------------------------------------------------------------
338 */
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 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)
340 {
341     EAS_I32 temp;
342     EAS_INT src, dest;
343 
344     /* NOTE: There are a lot of optimizations that can be done
345      * in the native implementations based on register
346      * availability, etc. For example, it may make sense to
347      * break this down into 8 separate routines:
348      *
349      * 1. Mono source to mono output
350      * 2. Mono source to stereo output
351      * 3. Stereo source to mono output
352      * 4. Stereo source to stereo output
353      * 5. Mono source to mono output - no gain change
354      * 6. Mono source to stereo output - no gain change
355      * 7. Stereo source to mono output - no gain change
356      * 8. Stereo source to stereo output - no gain change
357      *
358      * Other possibilities include loop unrolling, skipping
359      * a gain calculation every 2 or 4 samples, etc.
360      */
361 
362     /* no gain change, use fast loops */
363     if ((gainIncLeft == 0) && (gainIncRight == 0))
364     {
365         switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
366         {
367             /* mono to mono */
368             case 0:
369                 gainLeft >>= 15;
370                 for (src = dest = 0; src < numSamples; src++, dest++)
371                 {
372 
373                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
374                 }
375                 break;
376 
377             /* mono to stereo */
378             case MIX_FLAGS_STEREO_OUTPUT:
379                 gainLeft >>= 15;
380                 gainRight >>= 15;
381                 for (src = dest = 0; src < numSamples; src++, dest+=2)
382                 {
383                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
384                     pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS;
385                 }
386                 break;
387 
388             /* stereo to mono */
389             case MIX_FLAGS_STEREO_SOURCE:
390                 gainLeft >>= 15;
391                 gainRight >>= 15;
392                 for (src = dest = 0; src < numSamples; src+=2, dest++)
393                 {
394                     temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
395                     temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS);
396                     pMixBuffer[dest] += temp;
397                 }
398                 break;
399 
400             /* stereo to stereo */
401             case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
402                 gainLeft >>= 15;
403                 gainRight >>= 15;
404                 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
405                 {
406                     pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
407                     pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS;
408                 }
409                 break;
410         }
411     }
412 
413     /* gain change - do gain increment */
414     else
415     {
416         switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
417         {
418             /* mono to mono */
419             case 0:
420                 for (src = dest = 0; src < numSamples; src++, dest++)
421                 {
422                     gainLeft += gainIncLeft;
423                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
424                 }
425                 break;
426 
427             /* mono to stereo */
428             case MIX_FLAGS_STEREO_OUTPUT:
429                 for (src = dest = 0; src < numSamples; src++, dest+=2)
430                 {
431                     gainLeft += gainIncLeft;
432                     gainRight += gainIncRight;
433                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
434                     pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
435                 }
436                 break;
437 
438             /* stereo to mono */
439             case MIX_FLAGS_STEREO_SOURCE:
440                 for (src = dest = 0; src < numSamples; src+=2, dest++)
441                 {
442                     gainLeft += gainIncLeft;
443                     gainRight += gainIncRight;
444                     temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
445                     temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS);
446                     pMixBuffer[dest] += temp;
447                 }
448                 break;
449 
450             /* stereo to stereo */
451             case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
452                 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
453                 {
454                     gainLeft += gainIncLeft;
455                     gainRight += gainIncRight;
456                     pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
457                     pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
458                 }
459                 break;
460         }
461     }
462 }
463 #endif
464 #endif
465 
466