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 if (pWTIntFrame->frame.phaseIncrement) { 466 pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement); 467 } else { 468 pWTIntFrame->numSamples = numSamples; 469 } 470 471 /* sound will be done this frame */ 472 done = EAS_TRUE; 473 } 474 475 /* update data for off-chip synth */ 476 if (update) 477 { 478 pWTVoice->phaseFrac = endPhaseFrac; 479 pWTVoice->phaseAccum = endPhaseAccum; 480 } 481 482 return done; 483 } 484 485 /*---------------------------------------------------------------------------- 486 * WT_UpdateVoice() 487 *---------------------------------------------------------------------------- 488 * Purpose: 489 * Synthesize a block of samples for the given voice. 490 * Use linear interpolation. 491 * 492 * Inputs: 493 * pEASData - pointer to overall EAS data structure 494 * 495 * Outputs: 496 * number of samples actually written to buffer 497 * 498 * Side Effects: 499 * - samples are added to the presently free buffer 500 * 501 *---------------------------------------------------------------------------- 502 */ 503 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) 504 { 505 S_WT_VOICE *pWTVoice; 506 S_WT_INT_FRAME intFrame; 507 S_SYNTH_CHANNEL *pChannel; 508 const S_WT_REGION *pWTRegion; 509 const S_ARTICULATION *pArt; 510 EAS_I32 temp; 511 EAS_BOOL done; 512 513 #ifdef DLS_SYNTHESIZER 514 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH) 515 return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples); 516 #endif 517 518 /* establish pointers to critical data */ 519 pWTVoice = &pVoiceMgr->wtVoices[voiceNum]; 520 pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK]; 521 pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex]; 522 pChannel = &pSynth->channels[pVoice->channel & 15]; 523 intFrame.prevGain = pVoice->gain; 524 525 /* update the envelopes */ 526 WT_UpdateEG1(pWTVoice, &pArt->eg1); 527 WT_UpdateEG2(pWTVoice, &pArt->eg2); 528 529 /* update the LFO */ 530 WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq); 531 532 #ifdef _FILTER_ENABLED 533 /* calculate filter if library uses filter */ 534 if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED) 535 WT_UpdateFilter(pWTVoice, &intFrame, pArt); 536 else 537 intFrame.frame.k = 0; 538 #endif 539 540 /* update the gain */ 541 intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain); 542 543 /* calculate base pitch*/ 544 temp = pChannel->staticPitch + pWTRegion->tuning; 545 546 /* include global transpose */ 547 if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) 548 temp += pVoice->note * 100; 549 else 550 temp += (pVoice->note + pSynth->globalTranspose) * 100; 551 intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp); 552 553 /* call into engine to generate samples */ 554 intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer; 555 intFrame.pMixBuffer = pMixBuffer; 556 intFrame.numSamples = numSamples; 557 558 /* check for end of sample */ 559 if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd)) 560 done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES)); 561 else 562 done = EAS_FALSE; 563 564 if (intFrame.numSamples < 0) intFrame.numSamples = 0; 565 566 #ifdef EAS_SPLIT_WT_SYNTH 567 if (voiceNum < NUM_PRIMARY_VOICES) 568 { 569 #ifndef _SPLIT_WT_TEST_HARNESS 570 WT_ProcessVoice(pWTVoice, &intFrame); 571 #endif 572 } 573 else 574 WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer); 575 #else 576 WT_ProcessVoice(pWTVoice, &intFrame); 577 #endif 578 579 /* clear flag */ 580 pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; 581 582 /* if voice has finished, set flag for voice manager */ 583 if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted)) 584 done = EAS_TRUE; 585 586 /* if the update interval has elapsed, then force the current gain to the next 587 * gain since we never actually reach the next gain when ramping -- we just get 588 * very close to the target gain. 589 */ 590 pVoice->gain = (EAS_I16) intFrame.frame.gainTarget; 591 592 return done; 593 } 594 595 /*---------------------------------------------------------------------------- 596 * WT_UpdatePhaseInc() 597 *---------------------------------------------------------------------------- 598 * Purpose: 599 * Calculate the phase increment 600 * 601 * Inputs: 602 * pVoice - pointer to the voice being updated 603 * psRegion - pointer to the region 604 * psArticulation - pointer to the articulation 605 * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this 606 * voice during the duration of this synthesis 607 * pEASData - pointer to overall EAS data structure 608 * 609 * Outputs: 610 * 611 * Side Effects: 612 * set the phase increment for this voice 613 *---------------------------------------------------------------------------- 614 */ 615 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents) 616 { 617 EAS_I32 temp; 618 619 /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */ 620 temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, 621 ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7))); 622 623 /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */ 624 temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, 625 ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7))); 626 627 /* now multiply the (channel pressure + CC1) pitch values by the LFO value */ 628 temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp); 629 630 /* 631 add in the LFO pitch due to 632 channel pressure and CC1 along with 633 the LFO pitch, the EG2 pitch, and the 634 "static" pitch for this voice on this channel 635 */ 636 temp += pitchCents + 637 (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) + 638 (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch)); 639 640 /* convert from cents to linear phase increment */ 641 return EAS_Calculate2toX(temp); 642 } 643 644 /*---------------------------------------------------------------------------- 645 * WT_UpdateChannel() 646 *---------------------------------------------------------------------------- 647 * Purpose: 648 * Calculate and assign static channel parameters 649 * These values only need to be updated if one of the controller values 650 * for this channel changes 651 * 652 * Inputs: 653 * nChannel - channel to update 654 * pEASData - pointer to overall EAS data structure 655 * 656 * Outputs: 657 * 658 * Side Effects: 659 * - the given channel's static gain and static pitch are updated 660 *---------------------------------------------------------------------------- 661 */ 662 /*lint -esym(715, pVoiceMgr) reserved for future use */ 663 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) 664 { 665 EAS_I32 staticGain; 666 EAS_I32 pitchBend; 667 S_SYNTH_CHANNEL *pChannel; 668 669 pChannel = &pSynth->channels[channel]; 670 671 /* 672 nChannelGain = (CC7 * CC11)^2 * master volume 673 where CC7 == 100 by default, CC11 == 127, master volume == 32767 674 */ 675 staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7), 676 (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7)); 677 678 /* staticGain has to be squared */ 679 staticGain = MULT_EG1_EG1(staticGain, staticGain); 680 681 pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume); 682 683 /* 684 calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1) 685 However, if we use the EG1 macros, remember that EG1 has a full 686 scale value of 32768 (instead of 16384). So instead of multiplying 687 by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead 688 of 16384. This utilizes the fact that the EG1 macro places a binary 689 point 15 places to the left instead of 14 places. 690 */ 691 /*lint -e{703} <avoid multiply for performance>*/ 692 pitchBend = 693 (((EAS_I32)(pChannel->pitchBend) << 2) 694 - 32768); 695 696 pChannel->staticPitch = 697 MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity); 698 699 /* if this is not a drum channel, then add in the per-channel tuning */ 700 if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) 701 pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100); 702 703 /* clear update flag */ 704 pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; 705 return; 706 } 707 708 /*---------------------------------------------------------------------------- 709 * WT_UpdateGain() 710 *---------------------------------------------------------------------------- 711 * Purpose: 712 * Calculate and assign static voice parameters as part of WT_UpdateVoice() 713 * 714 * Inputs: 715 * pVoice - ptr to the synth voice that we want to synthesize 716 * pEASData - pointer to overall EAS data structure 717 * 718 * Outputs: 719 * 720 * Side Effects: 721 * - various voice parameters are calculated and assigned 722 * 723 *---------------------------------------------------------------------------- 724 */ 725 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain) 726 { 727 EAS_I32 lfoGain; 728 EAS_I32 temp; 729 730 /* 731 If this voice was stolen, then the velocity is actually 732 for the new note, not the note that we are currently ramping down. 733 So we really shouldn't use this velocity. However, that would require 734 more memory to store the velocity value, and the improvement may 735 not be sufficient to warrant the added memory. 736 */ 737 /* velocity is fixed at note start for a given voice and must be squared */ 738 temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7); 739 temp = MULT_EG1_EG1(temp, temp); 740 741 /* region gain is fixed as part of the articulation */ 742 temp = MULT_EG1_EG1(temp, gain); 743 744 /* include the channel gain */ 745 temp = MULT_EG1_EG1(temp, pChannel->staticGain); 746 747 /* calculate LFO gain using an approximation for 10^x */ 748 lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain); 749 lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS); 750 751 /* convert from a dB-like value to linear gain */ 752 lfoGain = EAS_Calculate2toX(lfoGain); 753 temp = MULT_EG1_EG1(temp, lfoGain); 754 755 /* calculate the voice's gain */ 756 temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value); 757 758 return temp; 759 } 760 761 /*---------------------------------------------------------------------------- 762 * WT_UpdateEG1() 763 *---------------------------------------------------------------------------- 764 * Purpose: 765 * Calculate the EG1 envelope for the given voice (but do not update any 766 * state) 767 * 768 * Inputs: 769 * pVoice - ptr to the voice whose envelope we want to update 770 * nVoice - this voice's number - used only for debug 771 * pEASData - pointer to overall EAS data structure 772 * 773 * Outputs: 774 * nValue - the envelope value 775 * 776 * Side Effects: 777 * - updates EG1 state value for the given voice 778 *---------------------------------------------------------------------------- 779 */ 780 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) 781 { 782 EAS_I32 temp; 783 784 switch (pWTVoice->eg1State) 785 { 786 case eEnvelopeStateAttack: 787 temp = pWTVoice->eg1Value + pWTVoice->eg1Increment; 788 789 /* check if we have reached peak amplitude */ 790 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) 791 { 792 /* limit the volume */ 793 temp = SYNTH_FULL_SCALE_EG1_GAIN; 794 795 /* prepare to move to decay state */ 796 pWTVoice->eg1State = eEnvelopeStateDecay; 797 pWTVoice->eg1Increment = pEnv->decayTime; 798 } 799 800 break; 801 802 /* exponential decay */ 803 case eEnvelopeStateDecay: 804 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); 805 806 /* check if we have reached sustain level */ 807 if (temp <= pEnv->sustainLevel) 808 { 809 /* enforce the sustain level */ 810 temp = pEnv->sustainLevel; 811 812 /* if sustain level is zero, skip sustain & release the voice */ 813 if (temp > 0) 814 pWTVoice->eg1State = eEnvelopeStateSustain; 815 816 /* move to sustain state */ 817 else 818 pWTVoice->eg1State = eEnvelopeStateMuted; 819 } 820 821 break; 822 823 case eEnvelopeStateSustain: 824 return; 825 826 case eEnvelopeStateRelease: 827 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment); 828 829 /* if we hit zero, this voice isn't contributing any audio */ 830 if (temp <= 0) 831 { 832 temp = 0; 833 pWTVoice->eg1State = eEnvelopeStateMuted; 834 } 835 break; 836 837 /* voice is muted, set target to zero */ 838 case eEnvelopeStateMuted: 839 temp = 0; 840 break; 841 842 case eEnvelopeStateInvalid: 843 default: 844 temp = 0; 845 #ifdef _DEBUG_SYNTH 846 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n", 847 pWTVoice->eg1State); */ } 848 #endif 849 break; 850 851 } 852 853 pWTVoice->eg1Value = (EAS_I16) temp; 854 } 855 856 /*---------------------------------------------------------------------------- 857 * WT_UpdateEG2() 858 *---------------------------------------------------------------------------- 859 * Purpose: 860 * Update the EG2 envelope for the given voice 861 * 862 * Inputs: 863 * pVoice - ptr to the voice whose envelope we want to update 864 * pEASData - pointer to overall EAS data structure 865 * 866 * Outputs: 867 * 868 * Side Effects: 869 * - updates EG2 values for the given voice 870 *---------------------------------------------------------------------------- 871 */ 872 873 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv) 874 { 875 EAS_I32 temp; 876 877 switch (pWTVoice->eg2State) 878 { 879 case eEnvelopeStateAttack: 880 temp = pWTVoice->eg2Value + pWTVoice->eg2Increment; 881 882 /* check if we have reached peak amplitude */ 883 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN) 884 { 885 /* limit the volume */ 886 temp = SYNTH_FULL_SCALE_EG1_GAIN; 887 888 /* prepare to move to decay state */ 889 pWTVoice->eg2State = eEnvelopeStateDecay; 890 891 pWTVoice->eg2Increment = pEnv->decayTime; 892 } 893 894 break; 895 896 /* implement linear pitch decay in cents */ 897 case eEnvelopeStateDecay: 898 temp = pWTVoice->eg2Value -pWTVoice->eg2Increment; 899 900 /* check if we have reached sustain level */ 901 if (temp <= pEnv->sustainLevel) 902 { 903 /* enforce the sustain level */ 904 temp = pEnv->sustainLevel; 905 906 /* prepare to move to sustain state */ 907 pWTVoice->eg2State = eEnvelopeStateSustain; 908 } 909 break; 910 911 case eEnvelopeStateSustain: 912 return; 913 914 case eEnvelopeStateRelease: 915 temp = pWTVoice->eg2Value - pWTVoice->eg2Increment; 916 917 if (temp <= 0) 918 { 919 temp = 0; 920 pWTVoice->eg2State = eEnvelopeStateMuted; 921 } 922 923 break; 924 925 /* voice is muted, set target to zero */ 926 case eEnvelopeStateMuted: 927 temp = 0; 928 break; 929 930 case eEnvelopeStateInvalid: 931 default: 932 temp = 0; 933 #ifdef _DEBUG_SYNTH 934 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n", 935 pWTVoice->eg2State); */ } 936 #endif 937 break; 938 } 939 940 pWTVoice->eg2Value = (EAS_I16) temp; 941 } 942 943 /*---------------------------------------------------------------------------- 944 * WT_UpdateLFO () 945 *---------------------------------------------------------------------------- 946 * Purpose: 947 * Calculate the LFO for the given voice 948 * 949 * Inputs: 950 * pLFO - ptr to the LFO data 951 * phaseInc - phase increment 952 * 953 * Outputs: 954 * 955 * Side Effects: 956 * - updates LFO values for the given voice 957 *---------------------------------------------------------------------------- 958 */ 959 void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc) 960 { 961 962 /* To save memory, if m_nPhaseValue is negative, we are in the 963 * delay phase, and m_nPhaseValue represents the time left 964 * in the delay. 965 */ 966 if (pLFO->lfoPhase < 0) 967 { 968 pLFO->lfoPhase++; 969 return; 970 } 971 972 /* calculate LFO output from phase value */ 973 /*lint -e{701} Use shift for performance */ 974 pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2); 975 /*lint -e{502} <shortcut to turn sawtooth into triangle wave> */ 976 if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000)) 977 pLFO->lfoValue = ~pLFO->lfoValue; 978 979 /* update LFO phase */ 980 pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff; 981 } 982 983 #ifdef _FILTER_ENABLED 984 /*---------------------------------------------------------------------------- 985 * WT_UpdateFilter() 986 *---------------------------------------------------------------------------- 987 * Purpose: 988 * Update the Filter parameters 989 * 990 * Inputs: 991 * pVoice - ptr to the voice whose filter we want to update 992 * pEASData - pointer to overall EAS data structure 993 * 994 * Outputs: 995 * 996 * Side Effects: 997 * - updates Filter values for the given voice 998 *---------------------------------------------------------------------------- 999 */ 1000 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt) 1001 { 1002 EAS_I32 cutoff; 1003 1004 /* no need to calculate filter coefficients if it is bypassed */ 1005 if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY) 1006 { 1007 pIntFrame->frame.k = 0; 1008 return; 1009 } 1010 1011 /* determine the dynamic cutoff frequency */ 1012 cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc); 1013 cutoff += pArt->filterCutoff; 1014 1015 /* subtract the A5 offset and the sampling frequency */ 1016 cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS; 1017 1018 /* limit the cutoff frequency */ 1019 if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS) 1020 cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS; 1021 else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS) 1022 cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS; 1023 1024 WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ); 1025 } 1026 #endif 1027 1028 #if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER) 1029 /*---------------------------------------------------------------------------- 1030 * coef 1031 *---------------------------------------------------------------------------- 1032 * Table of filter coefficients for low-pass filter 1033 *---------------------------------------------------------------------------- 1034 * 1035 * polynomial coefficients are based on 8kHz sampling frequency 1036 * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x) 1037 * 1038 *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta 1039 *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2) 1040 *note: this is a power series in 2^x, not k*2^x 1041 *where k = (2*pi*440)/8kHz == convert octaves to radians 1042 * 1043 * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really 1044 * k2g0*k^0 = k2g0 1045 * k2g1*k^1 1046 * k2g2*k^2 1047 * 1048 * 1049 * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x) 1050 * 1051 *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta 1052 *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3) 1053 *note: this is a power series in 2^x, not k*2^x 1054 *where k = (2*pi*440)/8kHz == convert octaves to radians 1055 *we also include the optimization factor of 0.81 1056 * 1057 * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really 1058 * n1g0*k^0 = n1g0 1059 * n1g1*k^1 1060 * n1g2*k^2 1061 * n1g3*k^3 1062 * 1063 * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3 1064 *---------------------------------------------------------------------------- 1065 */ 1066 1067 static const EAS_I16 nk1g0 = -32768; 1068 static const EAS_I16 nk1g2 = 1580; 1069 static const EAS_I16 k2g0 = 32767; 1070 1071 static const EAS_I16 k2g1[] = 1072 { 1073 -11324, /* k2g1[0] = -0.3455751918948761 */ 1074 -10387, /* k2g1[1] = -0.3169878073928751 */ 1075 -9528, /* k2g1[2] = -0.29076528753345476 */ 1076 -8740, /* k2g1[3] = -0.2667120011011279 */ 1077 -8017, /* k2g1[4] = -0.24464850028971705 */ 1078 -7353, /* k2g1[5] = -0.22441018194495696 */ 1079 -6745, /* k2g1[6] = -0.20584605955455101 */ 1080 -6187, /* k2g1[7] = -0.18881763682420102 */ 1081 -5675, /* k2g1[8] = -0.1731978744360067 */ 1082 -5206, /* k2g1[9] = -0.15887024228080968 */ 1083 -4775, /* k2g1[10] = -0.14572785009373057 */ 1084 -4380, /* k2g1[11] = -0.13367265000706827 */ 1085 -4018, /* k2g1[12] = -0.1226147050712642 */ 1086 -3685, /* k2g1[13] = -0.11247151828678581 */ 1087 -3381, /* k2g1[14] = -0.10316741714122014 */ 1088 -3101, /* k2g1[15] = -0.0946329890599603 */ 1089 -2844, /* k2g1[16] = -0.08680456355870586 */ 1090 -2609, /* k2g1[17] = -0.07962373723441349 */ 1091 -2393, /* k2g1[18] = -0.07303693805092666 */ 1092 -2195, /* k2g1[19] = -0.06699502566866912 */ 1093 -2014, /* k2g1[20] = -0.06145292483669077 */ 1094 -1847, /* k2g1[21] = -0.056369289112013346 */ 1095 -1694, /* k2g1[22] = -0.05170619239747895 */ 1096 -1554, /* k2g1[23] = -0.04742884599684141 */ 1097 -1426, /* k2g1[24] = -0.043505339076210514 */ 1098 -1308, /* k2g1[25] = -0.03990640059558053 */ 1099 -1199, /* k2g1[26] = -0.03660518093435039 */ 1100 -1100, /* k2g1[27] = -0.03357705158166837 */ 1101 -1009, /* k2g1[28] = -0.030799421397205727 */ 1102 -926, /* k2g1[29] = -0.028251568071585884 */ 1103 -849 /* k2g1[30] = -0.025914483529091967 */ 1104 }; 1105 1106 static const EAS_I16 k2g2[] = 1107 { 1108 1957, /* k2g2[0] = 0.059711106626580836 */ 1109 1646, /* k2g2[1] = 0.05024063501786333 */ 1110 1385, /* k2g2[2] = 0.042272226217199664 */ 1111 1165, /* k2g2[3] = 0.03556764576567844 */ 1112 981, /* k2g2[4] = 0.029926444346999134 */ 1113 825, /* k2g2[5] = 0.025179964880280382 */ 1114 694, /* k2g2[6] = 0.02118630011706455 */ 1115 584, /* k2g2[7] = 0.01782604998793514 */ 1116 491, /* k2g2[8] = 0.014998751854573014 */ 1117 414, /* k2g2[9] = 0.012619876941179595 */ 1118 348, /* k2g2[10] = 0.010618303146468736 */ 1119 293, /* k2g2[11] = 0.008934188679954682 */ 1120 246, /* k2g2[12] = 0.007517182949855368 */ 1121 207, /* k2g2[13] = 0.006324921212866403 */ 1122 174, /* k2g2[14] = 0.005321757979794424 */ 1123 147, /* k2g2[15] = 0.004477701309210577 */ 1124 123, /* k2g2[16] = 0.00376751612730811 */ 1125 104, /* k2g2[17] = 0.0031699697655869644 */ 1126 87, /* k2g2[18] = 0.00266719715992703 */ 1127 74, /* k2g2[19] = 0.0022441667321724647 */ 1128 62, /* k2g2[20] = 0.0018882309854916855 */ 1129 52, /* k2g2[21] = 0.0015887483774966232 */ 1130 44, /* k2g2[22] = 0.0013367651661223448 */ 1131 37, /* k2g2[23] = 0.0011247477162958733 */ 1132 31, /* k2g2[24] = 0.0009463572640678758 */ 1133 26, /* k2g2[25] = 0.0007962604042473498 */ 1134 22, /* k2g2[26] = 0.0006699696356181593 */ 1135 18, /* k2g2[27] = 0.0005637091964589207 */ 1136 16, /* k2g2[28] = 0.00047430217920125243 */ 1137 13, /* k2g2[29] = 0.00039907554925166274 */ 1138 11 /* k2g2[30] = 0.00033578022828973666 */ 1139 }; 1140 1141 static const EAS_I16 n1g2[] = 1142 { 1143 3170, /* n1g2[0] = 0.0967319927350769 */ 1144 3036, /* n1g2[1] = 0.0926446051254155 */ 1145 2908, /* n1g2[2] = 0.08872992911818503 */ 1146 2785, /* n1g2[3] = 0.08498066682523227 */ 1147 2667, /* n1g2[4] = 0.08138982872895201 */ 1148 2554, /* n1g2[5] = 0.07795072065216213 */ 1149 2446, /* n1g2[6] = 0.0746569312785634 */ 1150 2343, /* n1g2[7] = 0.07150232020051943 */ 1151 2244, /* n1g2[8] = 0.06848100647187474 */ 1152 2149, /* n1g2[9] = 0.06558735764447099 */ 1153 2058, /* n1g2[10] = 0.06281597926792246 */ 1154 1971, /* n1g2[11] = 0.06016170483307614 */ 1155 1888, /* n1g2[12] = 0.05761958614040857 */ 1156 1808, /* n1g2[13] = 0.05518488407540374 */ 1157 1732, /* n1g2[14] = 0.052853059773715245 */ 1158 1659, /* n1g2[15] = 0.05061976615964251 */ 1159 1589, /* n1g2[16] = 0.04848083984214659 */ 1160 1521, /* n1g2[17] = 0.046432293353298 */ 1161 1457, /* n1g2[18] = 0.04447030771468711 */ 1162 1396, /* n1g2[19] = 0.04259122531793907 */ 1163 1337, /* n1g2[20] = 0.040791543106060944 */ 1164 1280, /* n1g2[21] = 0.03906790604290942 */ 1165 1226, /* n1g2[22] = 0.037417100858604564 */ 1166 1174, /* n1g2[23] = 0.035836050059229754 */ 1167 1125, /* n1g2[24] = 0.03432180618965023 */ 1168 1077, /* n1g2[25] = 0.03287154633875494 */ 1169 1032, /* n1g2[26] = 0.03148256687687814 */ 1170 988, /* n1g2[27] = 0.030152278415589925 */ 1171 946, /* n1g2[28] = 0.028878200980459685 */ 1172 906, /* n1g2[29] = 0.02765795938779331 */ 1173 868 /* n1g2[30] = 0.02648927881672521 */ 1174 }; 1175 1176 static const EAS_I16 n1g3[] = 1177 { 1178 -548, /* n1g3[0] = -0.016714088475899017 */ 1179 -481, /* n1g3[1] = -0.014683605122742116 */ 1180 -423, /* n1g3[2] = -0.012899791676436092 */ 1181 -371, /* n1g3[3] = -0.01133268185193299 */ 1182 -326, /* n1g3[4] = -0.00995594976868754 */ 1183 -287, /* n1g3[5] = -0.008746467702146129 */ 1184 -252, /* n1g3[6] = -0.00768391756106361 */ 1185 -221, /* n1g3[7] = -0.006750449563854721 */ 1186 -194, /* n1g3[8] = -0.005930382380083576 */ 1187 -171, /* n1g3[9] = -0.005209939699767622 */ 1188 -150, /* n1g3[10] = -0.004577018805123356 */ 1189 -132, /* n1g3[11] = -0.004020987256990177 */ 1190 -116, /* n1g3[12] = -0.003532504280467257 */ 1191 -102, /* n1g3[13] = -0.00310336384922047 */ 1192 -89, /* n1g3[14] = -0.002726356832432369 */ 1193 -78, /* n1g3[15] = -0.002395149888601605 */ 1194 -69, /* n1g3[16] = -0.0021041790717285314 */ 1195 -61, /* n1g3[17] = -0.0018485563625771063 */ 1196 -53, /* n1g3[18] = -0.001623987554831628 */ 1197 -47, /* n1g3[19] = -0.0014267001167177025 */ 1198 -41, /* n1g3[20] = -0.0012533798162347005 */ 1199 -36, /* n1g3[21] = -0.0011011150453668693 */ 1200 -32, /* n1g3[22] = -0.0009673479079754438 */ 1201 -28, /* n1g3[23] = -0.0008498312496971563 */ 1202 -24, /* n1g3[24] = -0.0007465909079943587 */ 1203 -21, /* n1g3[25] = -0.0006558925481952733 */ 1204 -19, /* n1g3[26] = -0.0005762125284029567 */ 1205 -17, /* n1g3[27] = -0.0005062123038325457 */ 1206 -15, /* n1g3[28] = -0.0004447159405951901 */ 1207 -13, /* n1g3[29] = -0.00039069036118270117 */ 1208 -11 /* n1g3[30] = -0.00034322798979677605 */ 1209 }; 1210 1211 /*---------------------------------------------------------------------------- 1212 * WT_SetFilterCoeffs() 1213 *---------------------------------------------------------------------------- 1214 * Purpose: 1215 * Update the Filter parameters 1216 * 1217 * Inputs: 1218 * pVoice - ptr to the voice whose filter we want to update 1219 * pEASData - pointer to overall EAS data structure 1220 * 1221 * Outputs: 1222 * 1223 * Side Effects: 1224 * - updates Filter values for the given voice 1225 *---------------------------------------------------------------------------- 1226 */ 1227 void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance) 1228 { 1229 EAS_I32 temp; 1230 1231 /* 1232 Convert the cutoff, which has had A5 subtracted, using the 2^x approx 1233 Note, this cutoff is related to theta cutoff by 1234 theta = k * 2^x 1235 We use 2^x and incorporate k in the power series coefs instead 1236 */ 1237 cutoff = EAS_Calculate2toX(cutoff); 1238 1239 /* calculate b2 coef */ 1240 temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]); 1241 temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp); 1242 pIntFrame->frame.b2 = temp; 1243 1244 /* calculate b1 coef */ 1245 temp = MULT_AUDIO_COEF(cutoff, nk1g2); 1246 temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp); 1247 temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2); 1248 pIntFrame->frame.b1 = temp >> 1; 1249 1250 /* calculate K coef */ 1251 temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]); 1252 temp = MULT_AUDIO_COEF(cutoff, temp); 1253 temp = MULT_AUDIO_COEF(cutoff, temp); 1254 pIntFrame->frame.k = temp; 1255 } 1256 #endif 1257 1258