eas_mixer.c revision 7df30109963092559d3760c0661a020f9daf1030
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