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