eas_mixer.c revision a8c89077d78769bf4840fa91609edc51fe2fa02d
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
46EAS_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*/
73EAS_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*/
107void 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*/
135void 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*/
266void 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*/
310EAS_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*/
338void 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