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