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