1 /*---------------------------------------------------------------------------- 2 * 3 * File: 4 * eas_wtsynth.c 5 * 6 * Contents and purpose: 7 * Implements the synthesizer functions. 8 * 9 * Copyright Sonic Network Inc. 2004 10 11 * Licensed under the Apache License, Version 2.0 (the "License"); 12 * you may not use this file except in compliance with the License. 13 * You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * 23 *---------------------------------------------------------------------------- 24 * Revision Control: 25 * $Revision: 795 $ 26 * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ 27 *---------------------------------------------------------------------------- 28 */ 29 30 // includes 31 #define LOG_TAG "SYNTH" 32 #include "log/log.h" 33 #include <cutils/log.h> 34 35 #include "eas_data.h" 36 #include "eas_report.h" 37 #include "eas_host.h" 38 #include "eas_math.h" 39 #include "eas_synth_protos.h" 40 #include "eas_wtsynth.h" 41 #include "eas_pan.h" 42 43 #ifdef DLS_SYNTHESIZER 44 #include "eas_dlssynth.h" 45 #endif 46 47 #ifdef _METRICS_ENABLED 48 #include "eas_perf.h" 49 #endif 50 51 /* local prototypes */ 52 static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr); 53 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); 54 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); 55 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); 56 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); 57 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); 58 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); 59 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents); 60 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain); 61 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); 62 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv); 63 64 #ifdef EAS_SPLIT_WT_SYNTH 65 extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer); 66 extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain); 67 #endif 68 69 #ifdef _FILTER_ENABLED 70 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt); 71 #endif 72 73 #ifdef _STATS 74 extern double statsPhaseIncrement; 75 extern double statsMaxPhaseIncrement; 76 extern long statsPhaseSampleCount; 77 extern double statsSampleSize; 78 extern long statsSampleCount; 79 #endif 80 81 /*---------------------------------------------------------------------------- 82 * Synthesizer interface 83 *---------------------------------------------------------------------------- 84 */ 85 86 const S_SYNTH_INTERFACE wtSynth = 87 { 88 WT_Initialize, 89 WT_StartVoice, 90 WT_UpdateVoice, 91 WT_ReleaseVoice, 92 WT_MuteVoice, 93 WT_SustainPedal, 94 WT_UpdateChannel 95 }; 96 97 #ifdef EAS_SPLIT_WT_SYNTH 98 const S_FRAME_INTERFACE wtFrameInterface = 99 { 100 WTE_StartFrame, 101 WTE_EndFrame 102 }; 103 #endif 104 105 /*---------------------------------------------------------------------------- 106 * WT_Initialize() 107 *---------------------------------------------------------------------------- 108 * Purpose: 109 * 110 * Inputs: 111 * pVoice - pointer to voice to initialize 112 * 113 * Outputs: 114 * 115 *---------------------------------------------------------------------------- 116 */ 117 static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr) 118 { 119 EAS_INT i; 120 121 for (i = 0; i < NUM_WT_VOICES; i++) 122 { 123 124 pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX; 125 126 pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE; 127 pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE; 128 pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT; 129 130 pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE; 131 pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE; 132 pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT; 133 134 /* left and right gain values are needed only if stereo output */ 135 #if (NUM_OUTPUT_CHANNELS == 2) 136 pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN; 137 pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN; 138 #endif 139 140 pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC; 141 pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT; 142 143 #ifdef _FILTER_ENABLED 144 pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO; 145 pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO; 146 #endif 147 } 148 149 return EAS_TRUE; 150 } 151 152 /*---------------------------------------------------------------------------- 153 * WT_ReleaseVoice() 154 *---------------------------------------------------------------------------- 155 * Purpose: 156 * The selected voice is being released. 157 * 158 * Inputs: 159 * pEASData - pointer to S_EAS_DATA 160 * pVoice - pointer to voice to release 161 * 162 * Outputs: 163 * None 164 *---------------------------------------------------------------------------- 165 */ 166 /*lint -esym(715, pVoice) used in some implementations */ 167 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) 168 { 169 S_WT_VOICE *pWTVoice; 170 const S_ARTICULATION *pArticulation; 171 172 #ifdef DLS_SYNTHESIZER 173 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 174 { 175 DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum); 176 return; 177 } 178 #endif 179 180 pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; 181 pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; 182 183 /* release EG1 */ 184 pWTVoice->eg1State = eEnvelopeStateRelease; 185 pWTVoice->eg1Increment = pArticulation->eg1.releaseTime; 186 187 /* 188 The spec says we should release EG2, but doing so with the current 189 voicing is causing clicks. This fix will need to be coordinated with 190 a new sound library release 191 */ 192 193 /* release EG2 */ 194 pWTVoice->eg2State = eEnvelopeStateRelease; 195 pWTVoice->eg2Increment = pArticulation->eg2.releaseTime; 196 } 197 198 /*---------------------------------------------------------------------------- 199 * WT_MuteVoice() 200 *---------------------------------------------------------------------------- 201 * Purpose: 202 * The selected voice is being muted. 203 * 204 * Inputs: 205 * pVoice - pointer to voice to release 206 * 207 * Outputs: 208 * None 209 *---------------------------------------------------------------------------- 210 */ 211 /*lint -esym(715, pSynth) used in some implementations */ 212 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) 213 { 214 215 #ifdef DLS_SYNTHESIZER 216 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 217 { 218 DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum); 219 return; 220 } 221 #endif 222 223 /* clear deferred action flags */ 224 pVoice->voiceFlags &= 225 ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | 226 VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | 227 VOICE_FLAG_DEFER_MUTE); 228 229 /* set the envelope state */ 230 pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted; 231 pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted; 232 } 233 234 /*---------------------------------------------------------------------------- 235 * WT_SustainPedal() 236 *---------------------------------------------------------------------------- 237 * Purpose: 238 * The selected voice is held due to sustain pedal 239 * 240 * Inputs: 241 * pVoice - pointer to voice to sustain 242 * 243 * Outputs: 244 * None 245 *---------------------------------------------------------------------------- 246 */ 247 /*lint -esym(715, pChannel) used in some implementations */ 248 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) 249 { 250 S_WT_VOICE *pWTVoice; 251 252 #ifdef DLS_SYNTHESIZER 253 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 254 { 255 DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum); 256 return; 257 } 258 #endif 259 260 /* don't catch the voice if below the sustain level */ 261 pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; 262 if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel) 263 return; 264 265 /* sustain flag is set, damper pedal is on */ 266 /* defer releasing this note until the damper pedal is off */ 267 pWTVoice->eg1State = eEnvelopeStateDecay; 268 pVoice->voiceState = eVoiceStatePlay; 269 270 /* 271 because sustain pedal is on, this voice 272 should defer releasing its note 273 */ 274 pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; 275 276 #ifdef _DEBUG_SYNTH 277 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ } 278 #endif 279 } 280 281 /*---------------------------------------------------------------------------- 282 * WT_StartVoice() 283 *---------------------------------------------------------------------------- 284 * Purpose: 285 * Assign the region for the given instrument using the midi key number 286 * and the RPN2 (coarse tuning) value. By using RPN2 as part of the 287 * region selection process, we reduce the amount a given sample has 288 * to be transposed by selecting the closest recorded root instead. 289 * 290 * This routine is the second half of SynthAssignRegion(). 291 * If the region was successfully found by SynthFindRegionIndex(), 292 * then assign the region's parameters to the voice. 293 * 294 * Setup and initialize the following voice parameters: 295 * m_nRegionIndex 296 * 297 * Inputs: 298 * pVoice - ptr to the voice we have assigned for this channel 299 * nRegionIndex - index of the region 300 * pEASData - pointer to overall EAS data structure 301 * 302 * Outputs: 303 * success - could find and assign the region for this voice's note otherwise 304 * failure - could not find nor assign the region for this voice's note 305 * 306 * Side Effects: 307 * psSynthObject->m_sVoice[].m_nRegionIndex is assigned 308 * psSynthObject->m_sVoice[] parameters are assigned 309 *---------------------------------------------------------------------------- 310 */ 311 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) 312 { 313 S_WT_VOICE *pWTVoice; 314 const S_WT_REGION *pRegion; 315 const S_ARTICULATION *pArt; 316 S_SYNTH_CHANNEL *pChannel; 317 318 #if (NUM_OUTPUT_CHANNELS == 2) 319 EAS_INT pan; 320 #endif 321 322 #ifdef EAS_SPLIT_WT_SYNTH 323 S_WT_CONFIG wtConfig; 324 #endif 325 326 /* no samples have been synthesized for this note yet */ 327 pVoice->regionIndex = regionIndex; 328 pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; 329 330 /* get the articulation index for this region */ 331 pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; 332 pChannel = &pSynth->channels[pVoice->channel & 15]; 333 334 /* update static channel parameters */ 335 if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) 336 WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); 337 338 #ifdef DLS_SYNTHESIZER 339 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 340 return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex); 341 #endif 342 343 pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]); 344 pWTVoice->artIndex = pRegion->artIndex; 345 346 #ifdef _DEBUG_SYNTH 347 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ } 348 #endif 349 350 pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; 351 352 /* MIDI note on puts this voice into attack state */ 353 pWTVoice->eg1State = eEnvelopeStateAttack; 354 pWTVoice->eg1Value = 0; 355 pWTVoice->eg1Increment = pArt->eg1.attackTime; 356 pWTVoice->eg2State = eEnvelopeStateAttack; 357 pWTVoice->eg2Value = 0; 358 pWTVoice->eg2Increment = pArt->eg2.attackTime; 359 360 /* init the LFO */ 361 pWTVoice->modLFO.lfoValue = 0; 362 pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay; 363 364 pVoice->gain = 0; 365 366 #if (NUM_OUTPUT_CHANNELS == 2) 367 /* 368 Get the Midi CC10 pan value for this voice's channel 369 convert the pan value to an "angle" representation suitable for 370 our sin, cos calculator. This representation is NOT necessarily the same 371 as the transform in the GM manuals because of our sin, cos calculator. 372 "angle" = (CC10 - 64)/128 373 */ 374 pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64; 375 pan += pArt->pan; 376 EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight); 377 #endif 378 379 #ifdef _FILTER_ENABLED 380 /* clear out the filter states */ 381 pWTVoice->filter.z1 = 0; 382 pWTVoice->filter.z2 = 0; 383 #endif 384 385 /* if this wave is to be generated using noise generator */ 386 if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR) 387 { 388 pWTVoice->phaseAccum = 4574296; 389 pWTVoice->loopStart = WT_NOISE_GENERATOR; 390 pWTVoice->loopEnd = 4574295; 391 } 392 393 /* normal sample */ 394 else 395 { 396 397 #ifdef EAS_SPLIT_WT_SYNTH 398 if (voiceNum < NUM_PRIMARY_VOICES) 399 pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; 400 else 401 pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; 402 #else 403 pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex]; 404 #endif 405 406 if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED) 407 { 408 #if defined (_8_BIT_SAMPLES) 409 pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart; 410 pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1; 411 #else //_16_BIT_SAMPLES 412 pWTVoice->loopStart = pWTVoice->phaseAccum + (pRegion->loopStart<<1); 413 pWTVoice->loopEnd = pWTVoice->phaseAccum + (pRegion->loopEnd<<1) - 2; 414 #endif 415 } 416 else { 417 #if defined (_8_BIT_SAMPLES) 418 pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1; 419 #else //_16_BIT_SAMPLES 420 pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 2; 421 #endif 422 } 423 } 424 425 #ifdef EAS_SPLIT_WT_SYNTH 426 /* configure off-chip voices */ 427 if (voiceNum >= NUM_PRIMARY_VOICES) 428 { 429 wtConfig.phaseAccum = pWTVoice->phaseAccum; 430 wtConfig.loopStart = pWTVoice->loopStart; 431 wtConfig.loopEnd = pWTVoice->loopEnd; 432 wtConfig.gain = pVoice->gain; 433 434 #if (NUM_OUTPUT_CHANNELS == 2) 435 wtConfig.gainLeft = pWTVoice->gainLeft; 436 wtConfig.gainRight = pWTVoice->gainRight; 437 #endif 438 439 WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer); 440 } 441 #endif 442 443 return EAS_SUCCESS; 444 } 445 446 /*---------------------------------------------------------------------------- 447 * WT_CheckSampleEnd 448 *---------------------------------------------------------------------------- 449 * Purpose: 450 * Check for end of sample and calculate number of samples to synthesize 451 * 452 * Inputs: 453 * 454 * Outputs: 455 * 456 * Notes: 457 * 458 *---------------------------------------------------------------------------- 459 */ 460 EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update) 461 { 462 EAS_U32 endPhaseAccum; 463 EAS_U32 endPhaseFrac; 464 EAS_I32 numSamples; 465 EAS_BOOL done = EAS_FALSE; 466 467 /* check to see if we hit the end of the waveform this time */ 468 /*lint -e{703} use shift for performance */ 469 endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS); 470 #if defined (_8_BIT_SAMPLES) 471 endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac); 472 #else //_16_BIT_SAMPLES 473 // Multiply by 2 for 16 bit processing module implementation 474 endPhaseAccum = pWTVoice->phaseAccum + (EAS_U32)(endPhaseFrac >> 14); 475 #endif 476 if (endPhaseAccum >= pWTVoice->loopEnd) 477 { 478 /* calculate how far current ptr is from end */ 479 numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum); 480 #if defined (_16_BIT_SAMPLES) 481 numSamples >>= 1; // Divide by 2 for 16 bit processing module implementation 482 #endif 483 /* now account for the fractional portion */ 484 /*lint -e{703} use shift for performance */ 485 numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac); 486 if (pWTIntFrame->frame.phaseIncrement) { 487 pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); 488 } else { 489 pWTIntFrame->numSamples = numSamples; 490 } 491 if (pWTIntFrame->numSamples < 0) { 492 ALOGE("b/26366256"); 493 android_errorWriteLog(0x534e4554, "26366256"); 494 pWTIntFrame->numSamples = 0; 495 } 496 497 /* sound will be done this frame */ 498 done = EAS_TRUE; 499 } 500 501 /* update data for off-chip synth */ 502 if (update) 503 { 504 pWTVoice->phaseFrac = endPhaseFrac; 505 pWTVoice->phaseAccum = endPhaseAccum; 506 } 507 508 return done; 509 } 510 511 /*---------------------------------------------------------------------------- 512 * WT_UpdateVoice() 513 *---------------------------------------------------------------------------- 514 * Purpose: 515 * Synthesize a block of samples for the given voice. 516 * Use linear interpolation. 517 * 518 * Inputs: 519 * pEASData - pointer to overall EAS data structure 520 * 521 * Outputs: 522 * number of samples actually written to buffer 523 * 524 * Side Effects: 525 * - samples are added to the presently free buffer 526 * 527 *---------------------------------------------------------------------------- 528 */ 529 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) 530 { 531 S_WT_VOICE *pWTVoice; 532 S_WT_INT_FRAME intFrame; 533 S_SYNTH_CHANNEL *pChannel; 534 const S_WT_REGION *pWTRegion; 535 const S_ARTICULATION *pArt; 536 EAS_I32 temp; 537 EAS_BOOL done; 538 539 #ifdef DLS_SYNTHESIZER 540 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 541 return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); 542 #endif 543 544 /* establish pointers to critical data */ 545 pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; 546 pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; 547 pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; 548 pChannel = &pSynth->channels[pVoice->channel & 15]; 549 intFrame.prevGain = pVoice->gain; 550 551 /* update the envelopes */ 552 WT_UpdateEG1(pWTVoice, &pArt->eg1); 553 WT_UpdateEG2(pWTVoice, &pArt->eg2); 554 555 /* update the LFO */ 556 WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); 557 558 #ifdef _FILTER_ENABLED 559 /* calculate filter if library uses filter */ 560 if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) 561 WT_UpdateFilter(pWTVoice, &intFrame, pArt); 562 else 563 intFrame.frame.k = 0; 564 #endif 565 566 /* update the gain */ 567 intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); 568 569 /* calculate base pitch*/ 570 temp = pChannel->staticPitch + pWTRegion->tuning; 571 572 /* include global transpose */ 573 if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) 574 temp += pVoice->note * 100; 575 else 576 temp += (pVoice->note + pSynth->globalTranspose) * 100; 577 intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); 578 temp = pWTVoice->loopEnd - pWTVoice->loopStart; 579 #ifdef _16_BIT_SAMPLES 580 temp >>= 1; 581 #endif 582 if (temp != 0) { 583 temp = temp << NUM_PHASE_FRAC_BITS; 584 if (intFrame.frame.phaseIncrement > temp) { 585 ALOGW("%p phaseIncrement=%d", pWTVoice, (int)intFrame.frame.phaseIncrement); 586 intFrame.frame.phaseIncrement %= temp; 587 } 588 } 589 590 /* call into engine to generate samples */ 591 intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; 592 intFrame.pMixBuffer = pMixBuffer; 593 intFrame.numSamples = numSamples; 594 595 /* check for end of sample */ 596 if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) 597 done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); 598 else 599 done = EAS_FALSE; 600 601 if (intFrame.numSamples < 0) intFrame.numSamples = 0; 602 603 if (intFrame.numSamples > BUFFER_SIZE_IN_MONO_SAMPLES) 604 intFrame.numSamples = BUFFER_SIZE_IN_MONO_SAMPLES; 605 606 #ifdef EAS_SPLIT_WT_SYNTH 607 if (voiceNum < NUM_PRIMARY_VOICES) 608 { 609 #ifndef _SPLIT_WT_TEST_HARNESS 610 WT_ProcessVoice(pWTVoice, &intFrame); 611 #endif 612 } 613 else 614 WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); 615 #else 616 WT_ProcessVoice(pWTVoice, &intFrame); 617 #endif 618 619 /* clear flag */ 620 pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; 621 622 /* if voice has finished, set flag for voice manager */ 623 if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) 624 done = EAS_TRUE; 625 626 /* if the update interval has elapsed, then force the current gain to the next 627 * gain since we never actually reach the next gain when ramping -- we just get 628 * very close to the target gain. 629 */ 630 pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; 631 632 return done; 633 } 634 635 /*---------------------------------------------------------------------------- 636 * WT_UpdatePhaseInc() 637 *---------------------------------------------------------------------------- 638 * Purpose: 639 * Calculate the phase increment 640 * 641 * Inputs: 642 * pVoice - pointer to the voice being updated 643 * psRegion - pointer to the region 644 * psArticulation - pointer to the articulation 645 * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this 646 * voice during the duration of this synthesis 647 * pEASData - pointer to overall EAS data structure 648 * 649 * Outputs: 650 * 651 * Side Effects: 652 * set the phase increment for this voice 653 *---------------------------------------------------------------------------- 654 */ 655 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) 656 { 657 EAS_I32 temp; 658 659 /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ 660 temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, 661 ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); 662 663 /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ 664 temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, 665 ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); 666 667 /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ 668 temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); 669 670 /* 671 add in the LFO pitch due to 672 channel pressure and CC1 along with 673 the LFO pitch, the EG2 pitch, and the 674 "static" pitch for this voice on this channel 675 */ 676 temp += pitchCents + 677 (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + 678 (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); 679 680 /* convert from cents to linear phase increment */ 681 return EAS_Calculate2toX(temp); 682 } 683 684 /*---------------------------------------------------------------------------- 685 * WT_UpdateChannel() 686 *---------------------------------------------------------------------------- 687 * Purpose: 688 * Calculate and assign static channel parameters 689 * These values only need to be updated if one of the controller values 690 * for this channel changes 691 * 692 * Inputs: 693 * nChannel - channel to update 694 * pEASData - pointer to overall EAS data structure 695 * 696 * Outputs: 697 * 698 * Side Effects: 699 * - the given channel's static gain and static pitch are updated 700 *---------------------------------------------------------------------------- 701 */ 702 /*lint -esym(715, pVoiceMgr) reserved for future use */ 703 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) 704 { 705 EAS_I32 staticGain; 706 EAS_I32 pitchBend; 707 S_SYNTH_CHANNEL *pChannel; 708 709 pChannel = &pSynth->channels[channel]; 710 711 /* 712 nChannelGain = (CC7 * CC11)^2 * master volume 713 where CC7 == 100 by default, CC11 == 127, master volume == 32767 714 */ 715 staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), 716 (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); 717 718 /* staticGain has to be squared */ 719 staticGain = MULT_EG1_EG1(staticGain, staticGain); 720 721 pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); 722 723 /* 724 calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) 725 However, if we use the EG1 macros, remember that EG1 has a full 726 scale value of 32768 (instead of 16384). So instead of multiplying 727 by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead 728 of 16384. This utilizes the fact that the EG1 macro places a binary 729 point 15 places to the left instead of 14 places. 730 */ 731 /*lint -e{703} <avoid multiply for performance>*/ 732 pitchBend = 733 (((EAS_I32)(pChannel->pitchBend) << 2) 734 - 32768); 735 736 pChannel->staticPitch = 737 MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); 738 739 /* if this is not a drum channel, then add in the per-channel tuning */ 740 if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) 741 pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); 742 743 /* clear update flag */ 744 pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; 745 return; 746 } 747 748 /*---------------------------------------------------------------------------- 749 * WT_UpdateGain() 750 *---------------------------------------------------------------------------- 751 * Purpose: 752 * Calculate and assign static voice parameters as part of WT_UpdateVoice() 753 * 754 * Inputs: 755 * pVoice - ptr to the synth voice that we want to synthesize 756 * pEASData - pointer to overall EAS data structure 757 * 758 * Outputs: 759 * 760 * Side Effects: 761 * - various voice parameters are calculated and assigned 762 * 763 *---------------------------------------------------------------------------- 764 */ 765 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) 766 { 767 EAS_I32 lfoGain; 768 EAS_I32 temp; 769 770 /* 771 If this voice was stolen, then the velocity is actually 772 for the new note, not the note that we are currently ramping down. 773 So we really shouldn't use this velocity. However, that would require 774 more memory to store the velocity value, and the improvement may 775 not be sufficient to warrant the added memory. 776 */ 777 /* velocity is fixed at note start for a given voice and must be squared */ 778 temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); 779 temp = MULT_EG1_EG1(temp, temp); 780 781 /* region gain is fixed as part of the articulation */ 782 temp = MULT_EG1_EG1(temp, gain); 783 784 /* include the channel gain */ 785 temp = MULT_EG1_EG1(temp, pChannel->staticGain); 786 787 /* calculate LFO gain using an approximation for 10^x */ 788 lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); 789 lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); 790 791 /* convert from a dB-like value to linear gain */ 792 lfoGain = EAS_Calculate2toX(lfoGain); 793 temp = MULT_EG1_EG1(temp, lfoGain); 794 795 /* calculate the voice's gain */ 796 temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); 797 798 return temp; 799 } 800 801 /*---------------------------------------------------------------------------- 802 * WT_UpdateEG1() 803 *---------------------------------------------------------------------------- 804 * Purpose: 805 * Calculate the EG1 envelope for the given voice (but do not update any 806 * state) 807 * 808 * Inputs: 809 * pVoice - ptr to the voice whose envelope we want to update 810 * nVoice - this voice's number - used only for debug 811 * pEASData - pointer to overall EAS data structure 812 * 813 * Outputs: 814 * nValue - the envelope value 815 * 816 * Side Effects: 817 * - updates EG1 state value for the given voice 818 *---------------------------------------------------------------------------- 819 */ 820 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) 821 { 822 EAS_I32 temp; 823 824 switch (pWTVoice->eg1State) 825 { 826 case eEnvelopeStateAttack: 827 temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; 828 829 /* check if we have reached peak amplitude */ 830 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) 831 { 832 /* limit the volume */ 833 temp = SYNTH_FULL_SCALE_EG1_GAIN; 834 835 /* prepare to move to decay state */ 836 pWTVoice->eg1State = eEnvelopeStateDecay; 837 pWTVoice->eg1Increment = pEnv->decayTime; 838 } 839 840 break; 841 842 /* exponential decay */ 843 case eEnvelopeStateDecay: 844 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); 845 846 /* check if we have reached sustain level */ 847 if (temp <= pEnv->sustainLevel) 848 { 849 /* enforce the sustain level */ 850 temp = pEnv->sustainLevel; 851 852 /* if sustain level is zero, skip sustain & release the voice */ 853 if (temp > 0) 854 pWTVoice->eg1State = eEnvelopeStateSustain; 855 856 /* move to sustain state */ 857 else 858 pWTVoice->eg1State = eEnvelopeStateMuted; 859 } 860 861 break; 862 863 case eEnvelopeStateSustain: 864 return; 865 866 case eEnvelopeStateRelease: 867 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); 868 869 /* if we hit zero, this voice isn't contributing any audio */ 870 if (temp <= 0) 871 { 872 temp = 0; 873 pWTVoice->eg1State = eEnvelopeStateMuted; 874 } 875 break; 876 877 /* voice is muted, set target to zero */ 878 case eEnvelopeStateMuted: 879 temp = 0; 880 break; 881 882 case eEnvelopeStateInvalid: 883 default: 884 temp = 0; 885 #ifdef _DEBUG_SYNTH 886 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", 887 pWTVoice->eg1State); */ } 888 #endif 889 break; 890 891 } 892 893 pWTVoice->eg1Value = (EAS_I16) temp; 894 } 895 896 /*---------------------------------------------------------------------------- 897 * WT_UpdateEG2() 898 *---------------------------------------------------------------------------- 899 * Purpose: 900 * Update the EG2 envelope for the given voice 901 * 902 * Inputs: 903 * pVoice - ptr to the voice whose envelope we want to update 904 * pEASData - pointer to overall EAS data structure 905 * 906 * Outputs: 907 * 908 * Side Effects: 909 * - updates EG2 values for the given voice 910 *---------------------------------------------------------------------------- 911 */ 912 913 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) 914 { 915 EAS_I32 temp; 916 917 switch (pWTVoice->eg2State) 918 { 919 case eEnvelopeStateAttack: 920 temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; 921 922 /* check if we have reached peak amplitude */ 923 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) 924 { 925 /* limit the volume */ 926 temp = SYNTH_FULL_SCALE_EG1_GAIN; 927 928 /* prepare to move to decay state */ 929 pWTVoice->eg2State = eEnvelopeStateDecay; 930 931 pWTVoice->eg2Increment = pEnv->decayTime; 932 } 933 934 break; 935 936 /* implement linear pitch decay in cents */ 937 case eEnvelopeStateDecay: 938 temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; 939 940 /* check if we have reached sustain level */ 941 if (temp <= pEnv->sustainLevel) 942 { 943 /* enforce the sustain level */ 944 temp = pEnv->sustainLevel; 945 946 /* prepare to move to sustain state */ 947 pWTVoice->eg2State = eEnvelopeStateSustain; 948 } 949 break; 950 951 case eEnvelopeStateSustain: 952 return; 953 954 case eEnvelopeStateRelease: 955 temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; 956 957 if (temp <= 0) 958 { 959 temp = 0; 960 pWTVoice->eg2State = eEnvelopeStateMuted; 961 } 962 963 break; 964 965 /* voice is muted, set target to zero */ 966 case eEnvelopeStateMuted: 967 temp = 0; 968 break; 969 970 case eEnvelopeStateInvalid: 971 default: 972 temp = 0; 973 #ifdef _DEBUG_SYNTH 974 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", 975 pWTVoice->eg2State); */ } 976 #endif 977 break; 978 } 979 980 pWTVoice->eg2Value = (EAS_I16) temp; 981 } 982 983 /*---------------------------------------------------------------------------- 984 * WT_UpdateLFO () 985 *---------------------------------------------------------------------------- 986 * Purpose: 987 * Calculate the LFO for the given voice 988 * 989 * Inputs: 990 * pLFO - ptr to the LFO data 991 * phaseInc - phase increment 992 * 993 * Outputs: 994 * 995 * Side Effects: 996 * - updates LFO values for the given voice 997 *---------------------------------------------------------------------------- 998 */ 999 void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) 1000 { 1001 1002 /* To save memory, if m_nPhaseValue is negative, we are in the 1003 * delay phase, and m_nPhaseValue represents the time left 1004 * in the delay. 1005 */ 1006 if (pLFO->lfoPhase < 0) 1007 { 1008 pLFO->lfoPhase++; 1009 return; 1010 } 1011 1012 /* calculate LFO output from phase value */ 1013 /*lint -e{701} Use shift for performance */ 1014 pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); 1015 /*lint -e{502} <shortcut to turn sawtooth into triangle wave> */ 1016 if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) 1017 pLFO->lfoValue = ~pLFO->lfoValue; 1018 1019 /* update LFO phase */ 1020 pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; 1021 } 1022 1023 #ifdef _FILTER_ENABLED 1024 /*---------------------------------------------------------------------------- 1025 * WT_UpdateFilter() 1026 *---------------------------------------------------------------------------- 1027 * Purpose: 1028 * Update the Filter parameters 1029 * 1030 * Inputs: 1031 * pVoice - ptr to the voice whose filter we want to update 1032 * pEASData - pointer to overall EAS data structure 1033 * 1034 * Outputs: 1035 * 1036 * Side Effects: 1037 * - updates Filter values for the given voice 1038 *---------------------------------------------------------------------------- 1039 */ 1040 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) 1041 { 1042 EAS_I32 cutoff; 1043 1044 /* no need to calculate filter coefficients if it is bypassed */ 1045 if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) 1046 { 1047 pIntFrame->frame.k = 0; 1048 return; 1049 } 1050 1051 /* determine the dynamic cutoff frequency */ 1052 cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); 1053 cutoff += pArt->filterCutoff; 1054 1055 /* subtract the A5 offset and the sampling frequency */ 1056 cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; 1057 1058 /* limit the cutoff frequency */ 1059 if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) 1060 cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; 1061 else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) 1062 cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; 1063 1064 WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); 1065 } 1066 #endif 1067 1068 #if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) 1069 /*---------------------------------------------------------------------------- 1070 * coef 1071 *---------------------------------------------------------------------------- 1072 * Table of filter coefficients for low-pass filter 1073 *---------------------------------------------------------------------------- 1074 * 1075 * polynomial coefficients are based on 8kHz sampling frequency 1076 * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) 1077 * 1078 *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta 1079 *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) 1080 *note: this is a power series in 2^x, not k*2^x 1081 *where k = (2*pi*440)/8kHz == convert octaves to radians 1082 * 1083 * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really 1084 * k2g0*k^0 = k2g0 1085 * k2g1*k^1 1086 * k2g2*k^2 1087 * 1088 * 1089 * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) 1090 * 1091 *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta 1092 *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) 1093 *note: this is a power series in 2^x, not k*2^x 1094 *where k = (2*pi*440)/8kHz == convert octaves to radians 1095 *we also include the optimization factor of 0.81 1096 * 1097 * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really 1098 * n1g0*k^0 = n1g0 1099 * n1g1*k^1 1100 * n1g2*k^2 1101 * n1g3*k^3 1102 * 1103 * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 1104 *---------------------------------------------------------------------------- 1105 */ 1106 1107 static const EAS_I16 nk1g0 = -32768; 1108 static const EAS_I16 nk1g2 = 1580; 1109 static const EAS_I16 k2g0 = 32767; 1110 1111 static const EAS_I16 k2g1[] = 1112 { 1113 -11324, /* k2g1[0] = -0.3455751918948761 */ 1114 -10387, /* k2g1[1] = -0.3169878073928751 */ 1115 -9528, /* k2g1[2] = -0.29076528753345476 */ 1116 -8740, /* k2g1[3] = -0.2667120011011279 */ 1117 -8017, /* k2g1[4] = -0.24464850028971705 */ 1118 -7353, /* k2g1[5] = -0.22441018194495696 */ 1119 -6745, /* k2g1[6] = -0.20584605955455101 */ 1120 -6187, /* k2g1[7] = -0.18881763682420102 */ 1121 -5675, /* k2g1[8] = -0.1731978744360067 */ 1122 -5206, /* k2g1[9] = -0.15887024228080968 */ 1123 -4775, /* k2g1[10] = -0.14572785009373057 */ 1124 -4380, /* k2g1[11] = -0.13367265000706827 */ 1125 -4018, /* k2g1[12] = -0.1226147050712642 */ 1126 -3685, /* k2g1[13] = -0.11247151828678581 */ 1127 -3381, /* k2g1[14] = -0.10316741714122014 */ 1128 -3101, /* k2g1[15] = -0.0946329890599603 */ 1129 -2844, /* k2g1[16] = -0.08680456355870586 */ 1130 -2609, /* k2g1[17] = -0.07962373723441349 */ 1131 -2393, /* k2g1[18] = -0.07303693805092666 */ 1132 -2195, /* k2g1[19] = -0.06699502566866912 */ 1133 -2014, /* k2g1[20] = -0.06145292483669077 */ 1134 -1847, /* k2g1[21] = -0.056369289112013346 */ 1135 -1694, /* k2g1[22] = -0.05170619239747895 */ 1136 -1554, /* k2g1[23] = -0.04742884599684141 */ 1137 -1426, /* k2g1[24] = -0.043505339076210514 */ 1138 -1308, /* k2g1[25] = -0.03990640059558053 */ 1139 -1199, /* k2g1[26] = -0.03660518093435039 */ 1140 -1100, /* k2g1[27] = -0.03357705158166837 */ 1141 -1009, /* k2g1[28] = -0.030799421397205727 */ 1142 -926, /* k2g1[29] = -0.028251568071585884 */ 1143 -849 /* k2g1[30] = -0.025914483529091967 */ 1144 }; 1145 1146 static const EAS_I16 k2g2[] = 1147 { 1148 1957, /* k2g2[0] = 0.059711106626580836 */ 1149 1646, /* k2g2[1] = 0.05024063501786333 */ 1150 1385, /* k2g2[2] = 0.042272226217199664 */ 1151 1165, /* k2g2[3] = 0.03556764576567844 */ 1152 981, /* k2g2[4] = 0.029926444346999134 */ 1153 825, /* k2g2[5] = 0.025179964880280382 */ 1154 694, /* k2g2[6] = 0.02118630011706455 */ 1155 584, /* k2g2[7] = 0.01782604998793514 */ 1156 491, /* k2g2[8] = 0.014998751854573014 */ 1157 414, /* k2g2[9] = 0.012619876941179595 */ 1158 348, /* k2g2[10] = 0.010618303146468736 */ 1159 293, /* k2g2[11] = 0.008934188679954682 */ 1160 246, /* k2g2[12] = 0.007517182949855368 */ 1161 207, /* k2g2[13] = 0.006324921212866403 */ 1162 174, /* k2g2[14] = 0.005321757979794424 */ 1163 147, /* k2g2[15] = 0.004477701309210577 */ 1164 123, /* k2g2[16] = 0.00376751612730811 */ 1165 104, /* k2g2[17] = 0.0031699697655869644 */ 1166 87, /* k2g2[18] = 0.00266719715992703 */ 1167 74, /* k2g2[19] = 0.0022441667321724647 */ 1168 62, /* k2g2[20] = 0.0018882309854916855 */ 1169 52, /* k2g2[21] = 0.0015887483774966232 */ 1170 44, /* k2g2[22] = 0.0013367651661223448 */ 1171 37, /* k2g2[23] = 0.0011247477162958733 */ 1172 31, /* k2g2[24] = 0.0009463572640678758 */ 1173 26, /* k2g2[25] = 0.0007962604042473498 */ 1174 22, /* k2g2[26] = 0.0006699696356181593 */ 1175 18, /* k2g2[27] = 0.0005637091964589207 */ 1176 16, /* k2g2[28] = 0.00047430217920125243 */ 1177 13, /* k2g2[29] = 0.00039907554925166274 */ 1178 11 /* k2g2[30] = 0.00033578022828973666 */ 1179 }; 1180 1181 static const EAS_I16 n1g2[] = 1182 { 1183 3170, /* n1g2[0] = 0.0967319927350769 */ 1184 3036, /* n1g2[1] = 0.0926446051254155 */ 1185 2908, /* n1g2[2] = 0.08872992911818503 */ 1186 2785, /* n1g2[3] = 0.08498066682523227 */ 1187 2667, /* n1g2[4] = 0.08138982872895201 */ 1188 2554, /* n1g2[5] = 0.07795072065216213 */ 1189 2446, /* n1g2[6] = 0.0746569312785634 */ 1190 2343, /* n1g2[7] = 0.07150232020051943 */ 1191 2244, /* n1g2[8] = 0.06848100647187474 */ 1192 2149, /* n1g2[9] = 0.06558735764447099 */ 1193 2058, /* n1g2[10] = 0.06281597926792246 */ 1194 1971, /* n1g2[11] = 0.06016170483307614 */ 1195 1888, /* n1g2[12] = 0.05761958614040857 */ 1196 1808, /* n1g2[13] = 0.05518488407540374 */ 1197 1732, /* n1g2[14] = 0.052853059773715245 */ 1198 1659, /* n1g2[15] = 0.05061976615964251 */ 1199 1589, /* n1g2[16] = 0.04848083984214659 */ 1200 1521, /* n1g2[17] = 0.046432293353298 */ 1201 1457, /* n1g2[18] = 0.04447030771468711 */ 1202 1396, /* n1g2[19] = 0.04259122531793907 */ 1203 1337, /* n1g2[20] = 0.040791543106060944 */ 1204 1280, /* n1g2[21] = 0.03906790604290942 */ 1205 1226, /* n1g2[22] = 0.037417100858604564 */ 1206 1174, /* n1g2[23] = 0.035836050059229754 */ 1207 1125, /* n1g2[24] = 0.03432180618965023 */ 1208 1077, /* n1g2[25] = 0.03287154633875494 */ 1209 1032, /* n1g2[26] = 0.03148256687687814 */ 1210 988, /* n1g2[27] = 0.030152278415589925 */ 1211 946, /* n1g2[28] = 0.028878200980459685 */ 1212 906, /* n1g2[29] = 0.02765795938779331 */ 1213 868 /* n1g2[30] = 0.02648927881672521 */ 1214 }; 1215 1216 static const EAS_I16 n1g3[] = 1217 { 1218 -548, /* n1g3[0] = -0.016714088475899017 */ 1219 -481, /* n1g3[1] = -0.014683605122742116 */ 1220 -423, /* n1g3[2] = -0.012899791676436092 */ 1221 -371, /* n1g3[3] = -0.01133268185193299 */ 1222 -326, /* n1g3[4] = -0.00995594976868754 */ 1223 -287, /* n1g3[5] = -0.008746467702146129 */ 1224 -252, /* n1g3[6] = -0.00768391756106361 */ 1225 -221, /* n1g3[7] = -0.006750449563854721 */ 1226 -194, /* n1g3[8] = -0.005930382380083576 */ 1227 -171, /* n1g3[9] = -0.005209939699767622 */ 1228 -150, /* n1g3[10] = -0.004577018805123356 */ 1229 -132, /* n1g3[11] = -0.004020987256990177 */ 1230 -116, /* n1g3[12] = -0.003532504280467257 */ 1231 -102, /* n1g3[13] = -0.00310336384922047 */ 1232 -89, /* n1g3[14] = -0.002726356832432369 */ 1233 -78, /* n1g3[15] = -0.002395149888601605 */ 1234 -69, /* n1g3[16] = -0.0021041790717285314 */ 1235 -61, /* n1g3[17] = -0.0018485563625771063 */ 1236 -53, /* n1g3[18] = -0.001623987554831628 */ 1237 -47, /* n1g3[19] = -0.0014267001167177025 */ 1238 -41, /* n1g3[20] = -0.0012533798162347005 */ 1239 -36, /* n1g3[21] = -0.0011011150453668693 */ 1240 -32, /* n1g3[22] = -0.0009673479079754438 */ 1241 -28, /* n1g3[23] = -0.0008498312496971563 */ 1242 -24, /* n1g3[24] = -0.0007465909079943587 */ 1243 -21, /* n1g3[25] = -0.0006558925481952733 */ 1244 -19, /* n1g3[26] = -0.0005762125284029567 */ 1245 -17, /* n1g3[27] = -0.0005062123038325457 */ 1246 -15, /* n1g3[28] = -0.0004447159405951901 */ 1247 -13, /* n1g3[29] = -0.00039069036118270117 */ 1248 -11 /* n1g3[30] = -0.00034322798979677605 */ 1249 }; 1250 1251 /*---------------------------------------------------------------------------- 1252 * WT_SetFilterCoeffs() 1253 *---------------------------------------------------------------------------- 1254 * Purpose: 1255 * Update the Filter parameters 1256 * 1257 * Inputs: 1258 * pVoice - ptr to the voice whose filter we want to update 1259 * pEASData - pointer to overall EAS data structure 1260 * 1261 * Outputs: 1262 * 1263 * Side Effects: 1264 * - updates Filter values for the given voice 1265 *---------------------------------------------------------------------------- 1266 */ 1267 void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) 1268 { 1269 EAS_I32 temp; 1270 1271 /* 1272 Convert the cutoff, which has had A5 subtracted, using the 2^x approx 1273 Note, this cutoff is related to theta cutoff by 1274 theta = k * 2^x 1275 We use 2^x and incorporate k in the power series coefs instead 1276 */ 1277 cutoff = EAS_Calculate2toX(cutoff); 1278 1279 /* calculate b2 coef */ 1280 temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); 1281 temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); 1282 pIntFrame->frame.b2 = temp; 1283 1284 /* calculate b1 coef */ 1285 temp = MULT_AUDIO_COEF(cutoff, nk1g2); 1286 temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); 1287 temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); 1288 pIntFrame->frame.b1 = temp >> 1; 1289 1290 /* calculate K coef */ 1291 temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); 1292 temp = MULT_AUDIO_COEF(cutoff, temp); 1293 temp = MULT_AUDIO_COEF(cutoff, temp); 1294 pIntFrame->frame.k = temp; 1295 } 1296 #endif 1297 1298