C++程序  |  465行  |  14.5 KB

/*----------------------------------------------------------------------------
 *
 * 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