• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
EAS_MixEngineInit(S_EAS_DATA * pEASData)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 */
EAS_MixEnginePrep(S_EAS_DATA * pEASData,EAS_I32 numSamples)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 */
EAS_MixEnginePost(S_EAS_DATA * pEASData,EAS_I32 numSamples)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 */
SynthMasterGain(long * pInputBuffer,EAS_PCM * pOutputBuffer,EAS_U16 nGain,EAS_U16 numSamples)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 */
EAS_MixEngineShutdown(S_EAS_DATA * pEASData)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 */
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)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