eas_fmsynth.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. /*----------------------------------------------------------------------------
  2. *
  3. * File:
  4. * fmsynth.c
  5. *
  6. * Contents and purpose:
  7. * Implements the high-level FM synthesizer functions.
  8. *
  9. * Copyright Sonic Network Inc. 2004
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. *
  22. *----------------------------------------------------------------------------
  23. * Revision Control:
  24. * $Revision: 795 $
  25. * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
  26. *----------------------------------------------------------------------------
  27. */
  28. // includes
  29. #include "eas_host.h"
  30. #include "eas_report.h"
  31. #include "eas_data.h"
  32. #include "eas_synth_protos.h"
  33. #include "eas_audioconst.h"
  34. #include "eas_fmengine.h"
  35. #include "eas_math.h"
  36. /* option sanity check */
  37. #ifdef _REVERB
  38. #error "No reverb for FM synthesizer"
  39. #endif
  40. #ifdef _CHORUS
  41. #error "No chorus for FM synthesizer"
  42. #endif
  43. /*
  44. * WARNING: These macros can cause unwanted side effects. Use them
  45. * with care. For example, min(x++,y++) will cause either x or y to be
  46. * incremented twice.
  47. */
  48. #define min(a,b) ((a) < (b) ? (a) : (b))
  49. #define max(a,b) ((a) > (b) ? (a) : (b))
  50. /* pivot point for keyboard scalars */
  51. #define EG_SCALE_PIVOT_POINT 64
  52. #define KEY_SCALE_PIVOT_POINT 36
  53. /* This number is the negative of the frequency of the note (in cents) of
  54. * the sine wave played at unity. The number can be calculated as follows:
  55. *
  56. * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE)
  57. *
  58. * 8.17578 is a reference to the frequency of MIDI note 0
  59. */
  60. #if defined (_SAMPLE_RATE_8000)
  61. #define MAGIC_NUMBER 1279
  62. #elif defined (_SAMPLE_RATE_16000)
  63. #define MAGIC_NUMBER 79
  64. #elif defined (_SAMPLE_RATE_20000)
  65. #define MAGIC_NUMBER -308
  66. #elif defined (_SAMPLE_RATE_22050)
  67. #define MAGIC_NUMBER -477
  68. #elif defined (_SAMPLE_RATE_24000)
  69. #define MAGIC_NUMBER -623
  70. #elif defined (_SAMPLE_RATE_32000)
  71. #define MAGIC_NUMBER -1121
  72. #elif defined (_SAMPLE_RATE_44100)
  73. #define MAGIC_NUMBER -1677
  74. #elif defined (_SAMPLE_RATE_48000)
  75. #define MAGIC_NUMBER -1823
  76. #endif
  77. /* externs */
  78. extern const EAS_I16 fmControlTable[128];
  79. extern const EAS_U16 fmRateTable[256];
  80. extern const EAS_U16 fmAttackTable[16];
  81. extern const EAS_U8 fmDecayTable[16];
  82. extern const EAS_U8 fmReleaseTable[16];
  83. extern const EAS_U8 fmScaleTable[16];
  84. /* local prototypes */
  85. /*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */
  86. static EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; }
  87. static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
  88. static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
  89. static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
  90. static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
  91. static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
  92. static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
  93. /*----------------------------------------------------------------------------
  94. * Synthesizer interface
  95. *----------------------------------------------------------------------------
  96. */
  97. const S_SYNTH_INTERFACE fmSynth =
  98. {
  99. FM_Initialize,
  100. FM_StartVoice,
  101. FM_UpdateVoice,
  102. FM_ReleaseVoice,
  103. FM_MuteVoice,
  104. FM_SustainPedal,
  105. FM_UpdateChannel
  106. };
  107. #ifdef FM_OFFBOARD
  108. const S_FRAME_INTERFACE fmFrameInterface =
  109. {
  110. FM_StartFrame,
  111. FM_EndFrame
  112. };
  113. #endif
  114. /*----------------------------------------------------------------------------
  115. * inline functions
  116. *----------------------------------------------------------------------------
  117. */
  118. EAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum)
  119. {
  120. return &pVoiceMgr->fmVoices[voiceNum];
  121. }
  122. EAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
  123. {
  124. return &pSynth->channels[pVoice->channel & 15];
  125. }
  126. EAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
  127. {
  128. #ifdef _SECONDARY_SYNTH
  129. return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK];
  130. #else
  131. return &pSynth->pEAS->pFMRegions[pVoice->regionIndex];
  132. #endif
  133. }
  134. /*----------------------------------------------------------------------------
  135. * FM_SynthIsOutputOperator
  136. *----------------------------------------------------------------------------
  137. * Purpose:
  138. * Returns true if the operator is a direct output and not muted
  139. *
  140. * Inputs:
  141. *
  142. * Outputs:
  143. * Returns boolean
  144. *----------------------------------------------------------------------------
  145. */
  146. static EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex)
  147. {
  148. /* see if voice is muted */
  149. if ((pRegion->oper[operIndex].gain & 0xfc) == 0)
  150. return 0;
  151. /* check based on mode */
  152. switch (pRegion->region.keyGroupAndFlags & 7)
  153. {
  154. /* mode 0 - all operators are external */
  155. case 0:
  156. return EAS_TRUE;
  157. /* mode 1 - operators 1-3 are external */
  158. case 1:
  159. if (operIndex != 0)
  160. return EAS_TRUE;
  161. break;
  162. /* mode 2 - operators 1 & 3 are external */
  163. case 2:
  164. if ((operIndex == 1) || (operIndex == 3))
  165. return EAS_TRUE;
  166. break;
  167. /* mode 2 - operators 1 & 2 are external */
  168. case 3:
  169. if ((operIndex == 1) || (operIndex == 2))
  170. return EAS_TRUE;
  171. break;
  172. /* modes 4 & 5 - operator 1 is external */
  173. case 4:
  174. case 5:
  175. if (operIndex == 1)
  176. return EAS_TRUE;
  177. break;
  178. default:
  179. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d",
  180. pRegion->region.keyGroupAndFlags & 7); */ }
  181. }
  182. return EAS_FALSE;
  183. }
  184. /*----------------------------------------------------------------------------
  185. * FM_CalcEGRate()
  186. *----------------------------------------------------------------------------
  187. * Purpose:
  188. *
  189. * Inputs:
  190. * nKeyNumber - MIDI note
  191. * nLogRate - logarithmic scale rate from patch data
  192. * nKeyScale - key scaling factor for this EG
  193. *
  194. * Outputs:
  195. * 16-bit linear multiplier
  196. *----------------------------------------------------------------------------
  197. */
  198. static EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale)
  199. {
  200. EAS_I32 temp;
  201. /* incorporate key scaling on release rate */
  202. temp = (EAS_I32) nLogRate << 7;
  203. temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale;
  204. /* saturate */
  205. temp = max(temp, 0);
  206. temp = min(temp, 32767);
  207. /* look up in rate table */
  208. /*lint -e{704} use shift for performance */
  209. return fmRateTable[temp >> 8];
  210. }
  211. /*----------------------------------------------------------------------------
  212. * FM_ReleaseVoice()
  213. *----------------------------------------------------------------------------
  214. * Purpose:
  215. * The selected voice is being released.
  216. *
  217. * Inputs:
  218. * psEASData - pointer to S_EAS_DATA
  219. * pVoice - pointer to voice to release
  220. *
  221. * Outputs:
  222. * None
  223. *----------------------------------------------------------------------------
  224. */
  225. static void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
  226. {
  227. EAS_INT operIndex;
  228. const S_FM_REGION *pRegion;
  229. S_FM_VOICE *pFMVoice;
  230. /* check to see if voice responds to NOTE-OFF's */
  231. pRegion = GetFMRegionPtr(pSynth, pVoice);
  232. if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT)
  233. return;
  234. /* set all envelopes to release state */
  235. pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
  236. for (operIndex = 0; operIndex < 4; operIndex++)
  237. {
  238. pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease;
  239. /* incorporate key scaling on release rate */
  240. pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
  241. pVoice->note,
  242. fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f],
  243. fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
  244. } /* end for (operIndex = 0; operIndex < 4; operIndex++) */
  245. }
  246. /*----------------------------------------------------------------------------
  247. * FM_MuteVoice()
  248. *----------------------------------------------------------------------------
  249. * Purpose:
  250. * The selected voice is being muted.
  251. *
  252. * Inputs:
  253. * pVoice - pointer to voice to release
  254. *
  255. * Outputs:
  256. * None
  257. *----------------------------------------------------------------------------
  258. */
  259. /*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */
  260. static void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
  261. {
  262. S_FM_VOICE *pFMVoice;
  263. /* clear deferred action flags */
  264. pVoice->voiceFlags &=
  265. ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
  266. VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
  267. VOICE_FLAG_DEFER_MUTE);
  268. /* set all envelopes to muted state */
  269. pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
  270. pFMVoice->oper[0].envState = eFMEnvelopeStateMuted;
  271. pFMVoice->oper[1].envState = eFMEnvelopeStateMuted;
  272. pFMVoice->oper[2].envState = eFMEnvelopeStateMuted;
  273. pFMVoice->oper[3].envState = eFMEnvelopeStateMuted;
  274. }
  275. /*----------------------------------------------------------------------------
  276. * FM_SustainPedal()
  277. *----------------------------------------------------------------------------
  278. * Purpose:
  279. * The selected voice is held due to sustain pedal
  280. *
  281. * Inputs:
  282. * pVoice - pointer to voice to sustain
  283. *
  284. * Outputs:
  285. * None
  286. *----------------------------------------------------------------------------
  287. */
  288. /*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */
  289. static void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
  290. {
  291. const S_FM_REGION *pRegion;
  292. S_FM_VOICE *pFMVoice;
  293. EAS_INT operIndex;
  294. pRegion = GetFMRegionPtr(pSynth, pVoice);
  295. pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
  296. /* check to see if any envelopes are above the sustain level */
  297. for (operIndex = 0; operIndex < 4; operIndex++)
  298. {
  299. /* if level control or envelope gain is zero, skip this envelope */
  300. if (((pRegion->oper[operIndex].gain & 0xfc) == 0) ||
  301. (pFMVoice->oper[operIndex].envGain == 0))
  302. {
  303. continue;
  304. }
  305. /* if the envelope gain is above the sustain level, we need to catch this voice */
  306. if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7))
  307. {
  308. /* reset envelope to decay state */
  309. pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
  310. pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
  311. pVoice->note,
  312. fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
  313. fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
  314. /* set voice to decay state */
  315. pVoice->voiceState = eVoiceStatePlay;
  316. /* set sustain flag */
  317. pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
  318. }
  319. } /* end for (operIndex = 0; operIndex < 4; operIndex++) */
  320. }
  321. /*----------------------------------------------------------------------------
  322. * FM_StartVoice()
  323. *----------------------------------------------------------------------------
  324. * Purpose:
  325. * Assign the region for the given instrument using the midi key number
  326. * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
  327. * region selection process, we reduce the amount a given sample has
  328. * to be transposed by selecting the closest recorded root instead.
  329. *
  330. * This routine is the second half of SynthAssignRegion().
  331. * If the region was successfully found by SynthFindRegionIndex(),
  332. * then assign the region's parameters to the voice.
  333. *
  334. * Setup and initialize the following voice parameters:
  335. * m_nRegionIndex
  336. *
  337. * Inputs:
  338. * pVoice - ptr to the voice we have assigned for this channel
  339. * nRegionIndex - index of the region
  340. * psEASData - pointer to overall EAS data structure
  341. *
  342. * Outputs:
  343. * success - could find and assign the region for this voice's note otherwise
  344. * failure - could not find nor assign the region for this voice's note
  345. *
  346. * Side Effects:
  347. * psSynthObject->m_sVoice[].m_nRegionIndex is assigned
  348. * psSynthObject->m_sVoice[] parameters are assigned
  349. *----------------------------------------------------------------------------
  350. */
  351. static EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
  352. {
  353. S_FM_VOICE *pFMVoice;
  354. S_SYNTH_CHANNEL *pChannel;
  355. const S_FM_REGION *pRegion;
  356. EAS_I32 temp;
  357. EAS_INT operIndex;
  358. /* establish pointers to data */
  359. pVoice->regionIndex = regionIndex;
  360. pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
  361. pChannel = GetChannelPtr(pSynth, pVoice);
  362. pRegion = GetFMRegionPtr(pSynth, pVoice);
  363. /* update static channel parameters */
  364. if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)
  365. FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15);
  366. /* init the LFO */
  367. pFMVoice->lfoValue = 0;
  368. pFMVoice->lfoPhase = 0;
  369. pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1);
  370. #if (NUM_OUTPUT_CHANNELS == 2)
  371. /* calculate pan gain values only if stereo output */
  372. /* set up panning only at note start */
  373. temp = (EAS_I32) pChannel->pan - 64;
  374. temp += (EAS_I32) pRegion->pan;
  375. if (temp < -64)
  376. temp = -64;
  377. if (temp > 64)
  378. temp = 64;
  379. pFMVoice->pan = (EAS_I8) temp;
  380. #endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
  381. /* no samples have been synthesized for this note yet */
  382. pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
  383. /* initialize gain value for anti-zipper filter */
  384. pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain);
  385. pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume);
  386. /* initialize the operators */
  387. for (operIndex = 0; operIndex < 4; operIndex++)
  388. {
  389. /* establish operator output gain level */
  390. /*lint -e{701} <use shift for performance> */
  391. pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7);
  392. /* check for linear velocity flag */
  393. /*lint -e{703} <use shift for performance> */
  394. if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY)
  395. temp = (EAS_I32) (pVoice->velocity - 127) << 5;
  396. else
  397. temp = (EAS_I32) fmControlTable[pVoice->velocity];
  398. /* scale velocity */
  399. /*lint -e{704} use shift for performance */
  400. temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7;
  401. /* include key scalar */
  402. temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f];
  403. /* saturate */
  404. temp = min(temp, 0);
  405. temp = max(temp, -32768);
  406. /* save static gain parameters */
  407. pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp);
  408. /* incorporate key scaling on decay rate */
  409. pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
  410. pVoice->note,
  411. fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
  412. fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
  413. /* if zero attack time, max out envelope and jump to decay state */
  414. if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0)
  415. {
  416. /* start out envelope at max */
  417. pFMVoice->oper[operIndex].envGain = 0x7fff;
  418. /* set envelope to decay state */
  419. pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
  420. }
  421. /* start envelope at zero and start in attack state */
  422. else
  423. {
  424. pFMVoice->oper[operIndex].envGain = 0;
  425. pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack;
  426. }
  427. }
  428. return EAS_SUCCESS;
  429. }
  430. /*----------------------------------------------------------------------------
  431. * FM_UpdateChannel()
  432. *----------------------------------------------------------------------------
  433. * Purpose:
  434. * Calculate and assign static channel parameters
  435. * These values only need to be updated if one of the controller values
  436. * for this channel changes.
  437. * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set.
  438. *
  439. * Inputs:
  440. * nChannel - channel to update
  441. * psEASData - pointer to overall EAS data structure
  442. *
  443. * Outputs:
  444. *
  445. * Side Effects:
  446. * - the given channel's static gain and static pitch are updated
  447. *----------------------------------------------------------------------------
  448. */
  449. /*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */
  450. static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
  451. {
  452. S_SYNTH_CHANNEL *pChannel;
  453. EAS_I32 temp;
  454. pChannel = &pSynth->channels[channel];
  455. /* convert CC7 volume controller to log scale */
  456. temp = fmControlTable[pChannel->volume];
  457. /* incorporate CC11 expression controller */
  458. temp += fmControlTable[pChannel->expression];
  459. /* saturate */
  460. pChannel->staticGain = (EAS_I16) max(temp,-32768);
  461. /* calculate pitch bend */
  462. /*lint -e{703} <avoid multiply for performance>*/
  463. temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768);
  464. temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity);
  465. /* include "magic number" compensation for sample rate and lookup table size */
  466. temp += MAGIC_NUMBER;
  467. /* if this is not a drum channel, then add in the per-channel tuning */
  468. if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
  469. temp += (pChannel->finePitch + (pChannel->coarsePitch * 100));
  470. /* save static pitch */
  471. pChannel->staticPitch = temp;
  472. /* Calculate LFO modulation depth */
  473. /* mod wheel to LFO depth */
  474. temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
  475. pChannel->modWheel << (NUM_EG1_FRAC_BITS -7));
  476. /* channel pressure to LFO depth */
  477. pChannel->lfoAmt = (EAS_I16) (temp +
  478. FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
  479. pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7)));
  480. /* clear update flag */
  481. pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
  482. return;
  483. }
  484. /*----------------------------------------------------------------------------
  485. * FM_UpdateLFO()
  486. *----------------------------------------------------------------------------
  487. * Purpose:
  488. * Calculate the LFO for the given voice
  489. *
  490. * Inputs:
  491. * pVoice - ptr to the voice whose LFO we want to update
  492. * psEASData - pointer to overall EAS data structure - used for debug only
  493. *
  494. * Outputs:
  495. *
  496. * Side Effects:
  497. * - updates LFO values for the given voice
  498. *----------------------------------------------------------------------------
  499. */
  500. static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion)
  501. {
  502. /* increment the LFO phase if the delay time has elapsed */
  503. if (!pFMVoice->lfoDelay)
  504. {
  505. /*lint -e{701} <use shift for performance> */
  506. pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]);
  507. /* square wave LFO? */
  508. if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE)
  509. pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767);
  510. /* trick to get a triangle wave out of a sawtooth */
  511. else
  512. {
  513. pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1);
  514. /*lint -e{502} <shortcut to turn sawtooth into sine wave> */
  515. if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000))
  516. pFMVoice->lfoValue = ~pFMVoice->lfoValue;
  517. }
  518. }
  519. /* still in delay */
  520. else
  521. pFMVoice->lfoDelay--;
  522. return;
  523. }
  524. /*----------------------------------------------------------------------------
  525. * FM_UpdateEG()
  526. *----------------------------------------------------------------------------
  527. * Purpose:
  528. * Calculate the synthesis parameters for an operator to be used during
  529. * the next buffer
  530. *
  531. * Inputs:
  532. * pVoice - pointer to the voice being updated
  533. * psEASData - pointer to overall EAS data structure
  534. *
  535. * Outputs:
  536. *
  537. * Side Effects:
  538. *
  539. *----------------------------------------------------------------------------
  540. */
  541. static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot)
  542. {
  543. EAS_U32 temp;
  544. EAS_BOOL done;
  545. /* set flag assuming the envelope is not done */
  546. done = EAS_FALSE;
  547. /* take appropriate action based on state */
  548. switch (pOper->envState)
  549. {
  550. case eFMEnvelopeStateAttack:
  551. /* the envelope is linear during the attack, so add the value */
  552. temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4];
  553. /* check for end of attack */
  554. if (temp >= 0x7fff)
  555. {
  556. pOper->envGain = 0x7fff;
  557. pOper->envState = eFMEnvelopeStateDecay;
  558. }
  559. else
  560. pOper->envGain = (EAS_U16) temp;
  561. break;
  562. case eFMEnvelopeStateDecay:
  563. /* decay is exponential, multiply by decay rate */
  564. pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
  565. /* check for sustain level reached */
  566. temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7;
  567. if (pOper->envGain <= (EAS_U16) temp)
  568. {
  569. /* if this is a one-shot patch, go directly to release phase */
  570. if (oneShot)
  571. {
  572. pOper->envRate = FM_CalcEGRate(
  573. pVoice->note,
  574. fmReleaseTable[pOperData->velocityRelease & 0x0f],
  575. fmScaleTable[pOperData->egKeyScale >> 4]);
  576. pOper->envState = eFMEnvelopeStateRelease;
  577. }
  578. /* normal sustaining type */
  579. else
  580. {
  581. pOper->envGain = (EAS_U16) temp;
  582. pOper->envState = eFMEnvelopeStateSustain;
  583. }
  584. }
  585. break;
  586. case eFMEnvelopeStateSustain:
  587. pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7);
  588. break;
  589. case eFMEnvelopeStateRelease:
  590. /* release is exponential, multiply by release rate */
  591. pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
  592. /* fully released */
  593. if (pOper->envGain == 0)
  594. {
  595. pOper->envGain = 0;
  596. pOper->envState = eFMEnvelopeStateMuted;
  597. done = EAS_TRUE;
  598. }
  599. break;
  600. case eFMEnvelopeStateMuted:
  601. pOper->envGain = 0;
  602. done = EAS_TRUE;
  603. break;
  604. default:
  605. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ }
  606. } /* end switch (pOper->m_eState) */
  607. return done;
  608. }
  609. /*----------------------------------------------------------------------------
  610. * FM_UpdateDynamic()
  611. *----------------------------------------------------------------------------
  612. * Purpose:
  613. * Calculate the synthesis parameters for this voice that will be used to
  614. * synthesize the next buffer
  615. *
  616. * Inputs:
  617. * pVoice - pointer to the voice being updated
  618. * psEASData - pointer to overall EAS data structure
  619. *
  620. * Outputs:
  621. * Returns EAS_TRUE if voice will be fully ramped to zero at the end of
  622. * the next synthesized buffer.
  623. *
  624. * Side Effects:
  625. *
  626. *----------------------------------------------------------------------------
  627. */
  628. static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel)
  629. {
  630. EAS_I32 temp;
  631. EAS_I32 pitch;
  632. EAS_I32 lfoPitch;
  633. EAS_INT operIndex;
  634. EAS_BOOL done;
  635. /* increment LFO phase */
  636. FM_UpdateLFO(pFMVoice, pRegion);
  637. /* base pitch in cents */
  638. pitch = pVoice->note * 100;
  639. /* LFO amount includes LFO depth from programming + channel dynamics */
  640. temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt;
  641. /* multiply by LFO output to get final pitch modulation */
  642. lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp);
  643. /* flag to indicate this voice is done */
  644. done = EAS_TRUE;
  645. /* iterate through operators to establish parameters */
  646. for (operIndex = 0; operIndex < 4; operIndex++)
  647. {
  648. EAS_BOOL bTemp;
  649. /* set base phase increment for each operator */
  650. temp = pRegion->oper[operIndex].tuning +
  651. pChannel->staticPitch;
  652. /* add vibrato effect unless it is disabled for this operator */
  653. if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0)
  654. temp += lfoPitch;
  655. /* if note is monotonic, bias to MIDI note 60 */
  656. if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE)
  657. temp += 6000;
  658. else
  659. temp += pitch;
  660. pFMVoice->oper[operIndex].pitch = (EAS_I16) temp;
  661. /* calculate envelope, returns true if done */
  662. bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT);
  663. /* check if all output envelopes have completed */
  664. if (FM_SynthIsOutputOperator(pRegion, operIndex))
  665. done = done && bTemp;
  666. }
  667. return done;
  668. }
  669. /*----------------------------------------------------------------------------
  670. * FM_UpdateVoice()
  671. *----------------------------------------------------------------------------
  672. * Purpose:
  673. * Synthesize a block of samples for the given voice.
  674. *
  675. * Inputs:
  676. * psEASData - pointer to overall EAS data structure
  677. *
  678. * Outputs:
  679. * number of samples actually written to buffer
  680. *
  681. * Side Effects:
  682. * - samples are added to the presently free buffer
  683. *
  684. *----------------------------------------------------------------------------
  685. */
  686. static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
  687. {
  688. S_SYNTH_CHANNEL *pChannel;
  689. const S_FM_REGION *pRegion;
  690. S_FM_VOICE *pFMVoice;
  691. S_FM_VOICE_CONFIG vCfg;
  692. S_FM_VOICE_FRAME vFrame;
  693. EAS_I32 temp;
  694. EAS_INT oper;
  695. EAS_U16 voiceGainTarget;
  696. EAS_BOOL done;
  697. /* setup some pointers */
  698. pChannel = GetChannelPtr(pSynth, pVoice);
  699. pRegion = GetFMRegionPtr(pSynth, pVoice);
  700. pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
  701. /* if the voice is just starting, get the voice configuration data */
  702. if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
  703. {
  704. /* split architecture may limit the number of voice starts */
  705. #ifdef MAX_VOICE_STARTS
  706. if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS)
  707. return EAS_FALSE;
  708. pVoiceMgr->numVoiceStarts++;
  709. #endif
  710. /* get initial parameters */
  711. vCfg.feedback = pRegion->feedback;
  712. vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain;
  713. #if (NUM_OUTPUT_CHANNELS == 2)
  714. vCfg.pan = pFMVoice->pan;
  715. #endif
  716. /* get voice mode */
  717. vCfg.flags = pRegion->region.keyGroupAndFlags & 7;
  718. /* get operator parameters */
  719. for (oper = 0; oper < 4; oper++)
  720. {
  721. /* calculate initial gain */
  722. vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
  723. vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain;
  724. /* copy noise waveform flag */
  725. if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE)
  726. vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper);
  727. }
  728. #ifdef FM_OFFBOARD
  729. FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer);
  730. #else
  731. FM_ConfigVoice(voiceNum, &vCfg, NULL);
  732. #endif
  733. /* clear startup flag */
  734. pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
  735. }
  736. /* calculate new synthesis parameters */
  737. done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel);
  738. /* calculate LFO gain modulation */
  739. /*lint -e{702} <use shift for performance> */
  740. temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT;
  741. /* include channel gain */
  742. temp += pChannel->staticGain;
  743. /* -32768 or lower is infinite attenuation */
  744. if (temp < -32767)
  745. voiceGainTarget = 0;
  746. /* translate to linear gain multiplier */
  747. else
  748. voiceGainTarget = EAS_LogToLinear16(temp);
  749. /* include synth master volume */
  750. voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume);
  751. /* save target values for this frame */
  752. vFrame.voiceGain = voiceGainTarget;
  753. /* assume voice output is zero */
  754. pVoice->gain = 0;
  755. /* save operator targets for this frame */
  756. for (oper = 0; oper < 4; oper++)
  757. {
  758. vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
  759. vFrame.pitch[oper] = pFMVoice->oper[oper].pitch;
  760. /* use the highest output envelope level as the gain for the voice stealing algorithm */
  761. if (FM_SynthIsOutputOperator(pRegion, oper))
  762. pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]);
  763. }
  764. /* consider voice gain multiplier in calculating gain for stealing algorithm */
  765. pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain);
  766. /* synthesize samples */
  767. #ifdef FM_OFFBOARD
  768. FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer);
  769. #else
  770. FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL);
  771. #endif
  772. return done;
  773. }