Home | History | Annotate | Download | only in lib_src
      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 */
     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 */
    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 */
    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 */
    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 */
    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 */
    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