mirror of
https://github.com/id-Software/DOOM-IOS2.git
synced 2026-03-20 17:10:05 +01:00
Initial Commit
This commit is contained in:
464
common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c
Executable file
464
common/embeddedaudiosynthesis/arm-fm-22k/lib_src/eas_mixer.c
Executable file
@@ -0,0 +1,464 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* File:
|
||||
* eas_mixer.c
|
||||
*
|
||||
* Contents and purpose:
|
||||
* This file contains the critical components of the mix engine that
|
||||
* must be optimized for best performance.
|
||||
*
|
||||
* Copyright Sonic Network Inc. 2005
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
* Revision Control:
|
||||
* $Revision: 706 $
|
||||
* $Date: 2007-05-31 17:22:51 -0700 (Thu, 31 May 2007) $
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//3 dls: This module is in the midst of being converted from a synth
|
||||
//3 specific module to a general purpose mix engine
|
||||
|
||||
/*------------------------------------
|
||||
* includes
|
||||
*------------------------------------
|
||||
*/
|
||||
#include "eas_data.h"
|
||||
#include "eas_host.h"
|
||||
#include "eas_math.h"
|
||||
#include "eas_mixer.h"
|
||||
#include "eas_config.h"
|
||||
#include "eas_report.h"
|
||||
|
||||
#ifdef _MAXIMIZER_ENABLED
|
||||
EAS_I32 MaximizerProcess (EAS_VOID_PTR pInstData, EAS_I32 *pSrc, EAS_I32 *pDst, EAS_I32 numSamples);
|
||||
#endif
|
||||
|
||||
/*------------------------------------
|
||||
* defines
|
||||
*------------------------------------
|
||||
*/
|
||||
|
||||
/* need to boost stereo by ~3dB to compensate for the panner */
|
||||
#define STEREO_3DB_GAIN_BOOST 512
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* EAS_MixEngineInit()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Prepares the mix engine for work, allocates buffers, locates effects modules, etc.
|
||||
*
|
||||
* Inputs:
|
||||
* pEASData - instance data
|
||||
* pInstData - pointer to variable to receive instance data handle
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
EAS_RESULT EAS_MixEngineInit (S_EAS_DATA *pEASData)
|
||||
{
|
||||
|
||||
/* check Configuration Module for mix buffer allocation */
|
||||
if (pEASData->staticMemoryModel)
|
||||
pEASData->pMixBuffer = EAS_CMEnumData(EAS_CM_MIX_BUFFER);
|
||||
else
|
||||
pEASData->pMixBuffer = EAS_HWMalloc(pEASData->hwInstData, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
|
||||
if (pEASData->pMixBuffer == NULL)
|
||||
{
|
||||
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate mix buffer memory\n"); */ }
|
||||
return EAS_ERROR_MALLOC_FAILED;
|
||||
}
|
||||
EAS_HWMemSet((void *)(pEASData->pMixBuffer), 0, BUFFER_SIZE_IN_MONO_SAMPLES * NUM_OUTPUT_CHANNELS * sizeof(EAS_I32));
|
||||
|
||||
return EAS_SUCCESS;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* EAS_MixEnginePrep()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Performs prep before synthesize a buffer of audio, such as clearing
|
||||
* audio buffers, etc.
|
||||
*
|
||||
* Inputs:
|
||||
* psEASData - pointer to overall EAS data structure
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
void EAS_MixEnginePrep (S_EAS_DATA *pEASData, EAS_I32 numSamples)
|
||||
{
|
||||
|
||||
/* clear the mix buffer */
|
||||
#if (NUM_OUTPUT_CHANNELS == 2)
|
||||
EAS_HWMemSet(pEASData->pMixBuffer, 0, numSamples * (EAS_I32) sizeof(long) * 2);
|
||||
#else
|
||||
EAS_HWMemSet(pEASData->pMixBuffer, 0, (EAS_I32) numSamples * (EAS_I32) sizeof(long));
|
||||
#endif
|
||||
|
||||
/* need to clear other side-chain effect buffers (chorus & reverb) */
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* EAS_MixEnginePost
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* This routine does the post-processing after all voices have been
|
||||
* synthesized. It calls any sweeteners and does the final mixdown to
|
||||
* the output buffer.
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* Notes:
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
void EAS_MixEnginePost (S_EAS_DATA *pEASData, EAS_I32 numSamples)
|
||||
{
|
||||
EAS_U16 gain;
|
||||
|
||||
//3 dls: Need to restore the mix engine metrics
|
||||
|
||||
/* calculate the gain multiplier */
|
||||
#ifdef _MAXIMIZER_ENABLED
|
||||
if (pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effect)
|
||||
{
|
||||
EAS_I32 temp;
|
||||
temp = MaximizerProcess(pEASData->effectsModules[EAS_MODULE_MAXIMIZER].effectData, pEASData->pMixBuffer, pEASData->pMixBuffer, numSamples);
|
||||
temp = (temp * pEASData->masterGain) >> 15;
|
||||
if (temp > 32767)
|
||||
gain = 32767;
|
||||
else
|
||||
gain = (EAS_U16) temp;
|
||||
}
|
||||
else
|
||||
gain = (EAS_U16) pEASData->masterGain;
|
||||
#else
|
||||
gain = (EAS_U16) pEASData->masterGain;
|
||||
#endif
|
||||
|
||||
/* Not using all the gain bits for now
|
||||
* Reduce the input to the compressor by 6dB to prevent saturation
|
||||
*/
|
||||
#ifdef _COMPRESSOR_ENABLED
|
||||
if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
|
||||
gain = gain >> 5;
|
||||
else
|
||||
gain = gain >> 4;
|
||||
#else
|
||||
gain = gain >> 4;
|
||||
#endif
|
||||
|
||||
/* convert 32-bit mix buffer to 16-bit output format */
|
||||
#if (NUM_OUTPUT_CHANNELS == 2)
|
||||
SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) ((EAS_U16) numSamples * 2));
|
||||
#else
|
||||
SynthMasterGain(pEASData->pMixBuffer, pEASData->pOutputAudioBuffer, gain, (EAS_U16) numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _ENHANCER_ENABLED
|
||||
/* enhancer effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_ENHANCER].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_ENHANCER].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _GRAPHIC_EQ_ENABLED
|
||||
/* graphic EQ effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_GRAPHIC_EQ].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _COMPRESSOR_ENABLED
|
||||
/* compressor effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_COMPRESSOR].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _WOW_ENABLED
|
||||
/* WOW requires a 32-bit buffer, borrow the mix buffer and
|
||||
* pass it as the destination buffer
|
||||
*/
|
||||
/*lint -e{740} temporarily passing a parameter through an existing I/F */
|
||||
if (pEASData->effectsModules[EAS_MODULE_WOW].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_WOW].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_WOW].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
(EAS_PCM*) pEASData->pMixBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _TONECONTROLEQ_ENABLED
|
||||
/* ToneControlEQ effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_TONECONTROLEQ].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _REVERB_ENABLED
|
||||
/* Reverb effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_REVERB].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_REVERB].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_REVERB].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
#ifdef _CHORUS_ENABLED
|
||||
/* Chorus effect */
|
||||
if (pEASData->effectsModules[EAS_MODULE_CHORUS].effectData)
|
||||
(*pEASData->effectsModules[EAS_MODULE_CHORUS].effect->pfProcess)
|
||||
(pEASData->effectsModules[EAS_MODULE_CHORUS].effectData,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
pEASData->pOutputAudioBuffer,
|
||||
numSamples);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifndef NATIVE_EAS_KERNEL
|
||||
/*----------------------------------------------------------------------------
|
||||
* SynthMasterGain
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Mixes down audio from 32-bit to 16-bit target buffer
|
||||
*
|
||||
* Inputs:
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
void SynthMasterGain (long *pInputBuffer, EAS_PCM *pOutputBuffer, EAS_U16 nGain, EAS_U16 numSamples) {
|
||||
|
||||
/* loop through the buffer */
|
||||
while (numSamples--) {
|
||||
long s;
|
||||
|
||||
/* read a sample from the input buffer and add some guard bits */
|
||||
s = *pInputBuffer++;
|
||||
|
||||
/* add some guard bits */
|
||||
/*lint -e{704} <avoid divide for performance>*/
|
||||
s = s >> 7;
|
||||
|
||||
/* apply master gain */
|
||||
s *= (long) nGain;
|
||||
|
||||
/* shift to lower 16-bits */
|
||||
/*lint -e{704} <avoid divide for performance>*/
|
||||
s = s >> 9;
|
||||
|
||||
/* saturate */
|
||||
s = SATURATE(s);
|
||||
|
||||
*pOutputBuffer++ = (EAS_PCM)s;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* EAS_MixEngineShutdown()
|
||||
*----------------------------------------------------------------------------
|
||||
* Purpose:
|
||||
* Shuts down effects modules and deallocates memory
|
||||
*
|
||||
* Inputs:
|
||||
* pEASData - instance data
|
||||
* pInstData - instance data handle
|
||||
*
|
||||
* Outputs:
|
||||
*
|
||||
* Side Effects:
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData)
|
||||
{
|
||||
|
||||
/* check Configuration Module for static memory allocation */
|
||||
if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL))
|
||||
EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer);
|
||||
|
||||
return EAS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef UNIFIED_MIXER
|
||||
#ifndef NATIVE_MIX_STREAM
|
||||
/*----------------------------------------------------------------------------
|
||||
* EAS_MixStream
|
||||
*----------------------------------------------------------------------------
|
||||
* Mix a 16-bit stream into a 32-bit buffer
|
||||
*
|
||||
* pInputBuffer 16-bit input buffer
|
||||
* pMixBuffer 32-bit mix buffer
|
||||
* numSamples number of samples to mix
|
||||
* gainLeft initial gain left or mono
|
||||
* gainRight initial gain right
|
||||
* gainLeft left gain increment per sample
|
||||
* gainRight right gain increment per sample
|
||||
* flags bit 0 = stereo source
|
||||
* bit 1 = stereo output
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
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)
|
||||
{
|
||||
EAS_I32 temp;
|
||||
EAS_INT src, dest;
|
||||
|
||||
/* NOTE: There are a lot of optimizations that can be done
|
||||
* in the native implementations based on register
|
||||
* availability, etc. For example, it may make sense to
|
||||
* break this down into 8 separate routines:
|
||||
*
|
||||
* 1. Mono source to mono output
|
||||
* 2. Mono source to stereo output
|
||||
* 3. Stereo source to mono output
|
||||
* 4. Stereo source to stereo output
|
||||
* 5. Mono source to mono output - no gain change
|
||||
* 6. Mono source to stereo output - no gain change
|
||||
* 7. Stereo source to mono output - no gain change
|
||||
* 8. Stereo source to stereo output - no gain change
|
||||
*
|
||||
* Other possibilities include loop unrolling, skipping
|
||||
* a gain calculation every 2 or 4 samples, etc.
|
||||
*/
|
||||
|
||||
/* no gain change, use fast loops */
|
||||
if ((gainIncLeft == 0) && (gainIncRight == 0))
|
||||
{
|
||||
switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
|
||||
{
|
||||
/* mono to mono */
|
||||
case 0:
|
||||
gainLeft >>= 15;
|
||||
for (src = dest = 0; src < numSamples; src++, dest++)
|
||||
{
|
||||
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
|
||||
/* mono to stereo */
|
||||
case MIX_FLAGS_STEREO_OUTPUT:
|
||||
gainLeft >>= 15;
|
||||
gainRight >>= 15;
|
||||
for (src = dest = 0; src < numSamples; src++, dest+=2)
|
||||
{
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
|
||||
pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
|
||||
/* stereo to mono */
|
||||
case MIX_FLAGS_STEREO_SOURCE:
|
||||
gainLeft >>= 15;
|
||||
gainRight >>= 15;
|
||||
for (src = dest = 0; src < numSamples; src+=2, dest++)
|
||||
{
|
||||
temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
|
||||
temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS);
|
||||
pMixBuffer[dest] += temp;
|
||||
}
|
||||
break;
|
||||
|
||||
/* stereo to stereo */
|
||||
case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
|
||||
gainLeft >>= 15;
|
||||
gainRight >>= 15;
|
||||
for (src = dest = 0; src < numSamples; src+=2, dest+=2)
|
||||
{
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
|
||||
pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* gain change - do gain increment */
|
||||
else
|
||||
{
|
||||
switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
|
||||
{
|
||||
/* mono to mono */
|
||||
case 0:
|
||||
for (src = dest = 0; src < numSamples; src++, dest++)
|
||||
{
|
||||
gainLeft += gainIncLeft;
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
|
||||
/* mono to stereo */
|
||||
case MIX_FLAGS_STEREO_OUTPUT:
|
||||
for (src = dest = 0; src < numSamples; src++, dest+=2)
|
||||
{
|
||||
gainLeft += gainIncLeft;
|
||||
gainRight += gainIncRight;
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
|
||||
/* stereo to mono */
|
||||
case MIX_FLAGS_STEREO_SOURCE:
|
||||
for (src = dest = 0; src < numSamples; src+=2, dest++)
|
||||
{
|
||||
gainLeft += gainIncLeft;
|
||||
gainRight += gainIncRight;
|
||||
temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS);
|
||||
pMixBuffer[dest] += temp;
|
||||
}
|
||||
break;
|
||||
|
||||
/* stereo to stereo */
|
||||
case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
|
||||
for (src = dest = 0; src < numSamples; src+=2, dest+=2)
|
||||
{
|
||||
gainLeft += gainIncLeft;
|
||||
gainRight += gainIncRight;
|
||||
pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user