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