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 numSamples--;
273 /* read a sample from the input buffer and add some guard bits */
274 s = *pInputBuffer++;
275
276 /* add some guard bits */
277 /*lint -e{704} <avoid divide for performance>*/
278 s = s >> 7;
279
280 /* apply master gain */
281 s *= (long) nGain;
282
283 /* shift to lower 16-bits */
284 /*lint -e{704} <avoid divide for performance>*/
285 s = s >> 9;
286
287 /* saturate */
288 s = SATURATE(s);
289
290 *pOutputBuffer++ = (EAS_PCM)s;
291 }
292 }
293 #endif
294
295 /*----------------------------------------------------------------------------
296 * EAS_MixEngineShutdown()
297 *----------------------------------------------------------------------------
298 * Purpose:
299 * Shuts down effects modules and deallocates memory
300 *
301 * Inputs:
302 * pEASData - instance data
303 * pInstData - instance data handle
304 *
305 * Outputs:
306 *
307 * Side Effects:
308 *
309 *----------------------------------------------------------------------------
310 */
EAS_MixEngineShutdown(S_EAS_DATA * pEASData)311 EAS_RESULT EAS_MixEngineShutdown (S_EAS_DATA *pEASData)
312 {
313
314 /* check Configuration Module for static memory allocation */
315 if (!pEASData->staticMemoryModel && (pEASData->pMixBuffer != NULL))
316 EAS_HWFree(pEASData->hwInstData, pEASData->pMixBuffer);
317
318 return EAS_SUCCESS;
319 }
320
321 #ifdef UNIFIED_MIXER
322 #ifndef NATIVE_MIX_STREAM
323 /*----------------------------------------------------------------------------
324 * EAS_MixStream
325 *----------------------------------------------------------------------------
326 * Mix a 16-bit stream into a 32-bit buffer
327 *
328 * pInputBuffer 16-bit input buffer
329 * pMixBuffer 32-bit mix buffer
330 * numSamples number of samples to mix
331 * gainLeft initial gain left or mono
332 * gainRight initial gain right
333 * gainLeft left gain increment per sample
334 * gainRight right gain increment per sample
335 * flags bit 0 = stereo source
336 * bit 1 = stereo output
337 *----------------------------------------------------------------------------
338 */
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 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)
340 {
341 EAS_I32 temp;
342 EAS_INT src, dest;
343
344 /* NOTE: There are a lot of optimizations that can be done
345 * in the native implementations based on register
346 * availability, etc. For example, it may make sense to
347 * break this down into 8 separate routines:
348 *
349 * 1. Mono source to mono output
350 * 2. Mono source to stereo output
351 * 3. Stereo source to mono output
352 * 4. Stereo source to stereo output
353 * 5. Mono source to mono output - no gain change
354 * 6. Mono source to stereo output - no gain change
355 * 7. Stereo source to mono output - no gain change
356 * 8. Stereo source to stereo output - no gain change
357 *
358 * Other possibilities include loop unrolling, skipping
359 * a gain calculation every 2 or 4 samples, etc.
360 */
361
362 /* no gain change, use fast loops */
363 if ((gainIncLeft == 0) && (gainIncRight == 0))
364 {
365 switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
366 {
367 /* mono to mono */
368 case 0:
369 gainLeft >>= 15;
370 for (src = dest = 0; src < numSamples; src++, dest++)
371 {
372
373 pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
374 }
375 break;
376
377 /* mono to stereo */
378 case MIX_FLAGS_STEREO_OUTPUT:
379 gainLeft >>= 15;
380 gainRight >>= 15;
381 for (src = dest = 0; src < numSamples; src++, dest+=2)
382 {
383 pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
384 pMixBuffer[dest+1] += (pInputBuffer[src] * gainRight) >> NUM_MIXER_GUARD_BITS;
385 }
386 break;
387
388 /* stereo to mono */
389 case MIX_FLAGS_STEREO_SOURCE:
390 gainLeft >>= 15;
391 gainRight >>= 15;
392 for (src = dest = 0; src < numSamples; src+=2, dest++)
393 {
394 temp = (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
395 temp += ((pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS);
396 pMixBuffer[dest] += temp;
397 }
398 break;
399
400 /* stereo to stereo */
401 case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
402 gainLeft >>= 15;
403 gainRight >>= 15;
404 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
405 {
406 pMixBuffer[dest] += (pInputBuffer[src] * gainLeft) >> NUM_MIXER_GUARD_BITS;
407 pMixBuffer[dest+1] += (pInputBuffer[src+1] * gainRight) >> NUM_MIXER_GUARD_BITS;
408 }
409 break;
410 }
411 }
412
413 /* gain change - do gain increment */
414 else
415 {
416 switch (flags & (MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT))
417 {
418 /* mono to mono */
419 case 0:
420 for (src = dest = 0; src < numSamples; src++, dest++)
421 {
422 gainLeft += gainIncLeft;
423 pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
424 }
425 break;
426
427 /* mono to stereo */
428 case MIX_FLAGS_STEREO_OUTPUT:
429 for (src = dest = 0; src < numSamples; src++, dest+=2)
430 {
431 gainLeft += gainIncLeft;
432 gainRight += gainIncRight;
433 pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
434 pMixBuffer[dest+1] += (pInputBuffer[src] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
435 }
436 break;
437
438 /* stereo to mono */
439 case MIX_FLAGS_STEREO_SOURCE:
440 for (src = dest = 0; src < numSamples; src+=2, dest++)
441 {
442 gainLeft += gainIncLeft;
443 gainRight += gainIncRight;
444 temp = (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
445 temp += ((pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS);
446 pMixBuffer[dest] += temp;
447 }
448 break;
449
450 /* stereo to stereo */
451 case MIX_FLAGS_STEREO_SOURCE | MIX_FLAGS_STEREO_OUTPUT:
452 for (src = dest = 0; src < numSamples; src+=2, dest+=2)
453 {
454 gainLeft += gainIncLeft;
455 gainRight += gainIncRight;
456 pMixBuffer[dest] += (pInputBuffer[src] * (gainLeft >> 15)) >> NUM_MIXER_GUARD_BITS;
457 pMixBuffer[dest+1] += (pInputBuffer[src+1] * (gainRight >> 15)) >> NUM_MIXER_GUARD_BITS;
458 }
459 break;
460 }
461 }
462 }
463 #endif
464 #endif
465
466