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