eas_smf.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. /*----------------------------------------------------------------------------
  2. *
  3. * File:
  4. * eas_smf.c
  5. *
  6. * Contents and purpose:
  7. * SMF Type 0 and 1 File Parser
  8. *
  9. * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls".
  10. *
  11. * Copyright Sonic Network Inc. 2005
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. *
  24. *----------------------------------------------------------------------------
  25. * Revision Control:
  26. * $Revision: 803 $
  27. * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $
  28. *----------------------------------------------------------------------------
  29. */
  30. #include "eas_data.h"
  31. #include "eas_miditypes.h"
  32. #include "eas_parser.h"
  33. #include "eas_report.h"
  34. #include "eas_host.h"
  35. #include "eas_midi.h"
  36. #include "eas_config.h"
  37. #include "eas_vm_protos.h"
  38. #include "eas_smfdata.h"
  39. #include "eas_smf.h"
  40. #ifdef JET_INTERFACE
  41. #include "jet_data.h"
  42. #endif
  43. //3 dls: The timebase for this module is adequate to keep MIDI and
  44. //3 digital audio synchronized for only a few minutes. It should be
  45. //3 sufficient for most mobile applications. If better accuracy is
  46. //3 required, more fractional bits should be added to the timebase.
  47. static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' };
  48. /* local prototypes */
  49. static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData);
  50. static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream);
  51. static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode);
  52. static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode);
  53. static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream);
  54. static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks);
  55. /*----------------------------------------------------------------------------
  56. *
  57. * SMF_Parser
  58. *
  59. * This structure contains the functional interface for the SMF parser
  60. *----------------------------------------------------------------------------
  61. */
  62. const S_FILE_PARSER_INTERFACE EAS_SMF_Parser =
  63. {
  64. SMF_CheckFileType,
  65. SMF_Prepare,
  66. SMF_Time,
  67. SMF_Event,
  68. SMF_State,
  69. SMF_Close,
  70. SMF_Reset,
  71. SMF_Pause,
  72. SMF_Resume,
  73. NULL,
  74. SMF_SetData,
  75. SMF_GetData,
  76. NULL
  77. };
  78. /*----------------------------------------------------------------------------
  79. * SMF_CheckFileType()
  80. *----------------------------------------------------------------------------
  81. * Purpose:
  82. * Check the file type to see if we can parse it
  83. *
  84. * Inputs:
  85. * pEASData - pointer to overall EAS data structure
  86. * handle - pointer to file handle
  87. *
  88. * Outputs:
  89. *
  90. *
  91. * Side Effects:
  92. *
  93. *----------------------------------------------------------------------------
  94. */
  95. EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
  96. {
  97. S_SMF_DATA* pSMFData;
  98. EAS_RESULT result;
  99. /* seek to starting offset - usually 0 */
  100. *ppHandle = NULL;
  101. if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
  102. return result;
  103. /* search through file for header - slow method */
  104. if (pEASData->searchHeaderFlag)
  105. {
  106. result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset);
  107. if (result != EAS_SUCCESS)
  108. return (result == EAS_EOF) ? EAS_SUCCESS : result;
  109. }
  110. /* read the first 4 bytes of the file - quick method */
  111. else {
  112. EAS_U8 header[4];
  113. EAS_I32 count;
  114. if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS)
  115. return result;
  116. /* check for 'MTrk' - return if no match */
  117. if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd'))
  118. return EAS_SUCCESS;
  119. }
  120. /* check for static memory allocation */
  121. if (pEASData->staticMemoryModel)
  122. pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA);
  123. else
  124. {
  125. pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA));
  126. EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA));
  127. }
  128. if (!pSMFData)
  129. return EAS_ERROR_MALLOC_FAILED;
  130. /* initialize some critical data */
  131. pSMFData->fileHandle = fileHandle;
  132. pSMFData->fileOffset = offset;
  133. pSMFData->pSynth = NULL;
  134. pSMFData->time = 0;
  135. pSMFData->state = EAS_STATE_OPEN;
  136. *ppHandle = pSMFData;
  137. return EAS_SUCCESS;
  138. }
  139. /*----------------------------------------------------------------------------
  140. * SMF_Prepare()
  141. *----------------------------------------------------------------------------
  142. * Purpose:
  143. * Prepare to parse the file. Allocates instance data (or uses static allocation for
  144. * static memory model).
  145. *
  146. * Inputs:
  147. * pEASData - pointer to overall EAS data structure
  148. * handle - pointer to file handle
  149. *
  150. * Outputs:
  151. *
  152. *
  153. * Side Effects:
  154. *
  155. *----------------------------------------------------------------------------
  156. */
  157. EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
  158. {
  159. S_SMF_DATA* pSMFData;
  160. EAS_RESULT result;
  161. /* check for valid state */
  162. pSMFData = (S_SMF_DATA *) pInstData;
  163. if (pSMFData->state != EAS_STATE_OPEN)
  164. return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
  165. /* instantiate a synthesizer */
  166. if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS)
  167. {
  168. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ }
  169. return result;
  170. }
  171. /* parse the file header and setup the individual stream parsers */
  172. if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS)
  173. return result;
  174. /* ready to play */
  175. pSMFData->state = EAS_STATE_READY;
  176. return EAS_SUCCESS;
  177. }
  178. /*----------------------------------------------------------------------------
  179. * SMF_Time()
  180. *----------------------------------------------------------------------------
  181. * Purpose:
  182. * Returns the time of the next event in msecs
  183. *
  184. * Inputs:
  185. * pEASData - pointer to overall EAS data structure
  186. * handle - pointer to file handle
  187. * pTime - pointer to variable to hold time of next event (in msecs)
  188. *
  189. * Outputs:
  190. *
  191. *
  192. * Side Effects:
  193. *
  194. *----------------------------------------------------------------------------
  195. */
  196. /*lint -esym(715, pEASData) reserved for future use */
  197. EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
  198. {
  199. S_SMF_DATA *pSMFData;
  200. pSMFData = (S_SMF_DATA*) pInstData;
  201. /* sanity check */
  202. #ifdef _CHECKED_BUILD
  203. if (pSMFData->state == EAS_STATE_STOPPED)
  204. {
  205. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ }
  206. }
  207. if (pSMFData->nextStream == NULL)
  208. {
  209. { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ }
  210. }
  211. #endif
  212. #if 0
  213. /* return time in milliseconds */
  214. /* if chase mode, lie about time */
  215. if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
  216. *pTime = 0;
  217. else
  218. #endif
  219. /*lint -e{704} use shift instead of division */
  220. *pTime = pSMFData->time >> 8;
  221. *pTime = pSMFData->time >> 8;
  222. return EAS_SUCCESS;
  223. }
  224. /*----------------------------------------------------------------------------
  225. * SMF_Event()
  226. *----------------------------------------------------------------------------
  227. * Purpose:
  228. * Parse the next event in the file
  229. *
  230. * Inputs:
  231. * pEASData - pointer to overall EAS data structure
  232. * handle - pointer to file handle
  233. *
  234. * Outputs:
  235. *
  236. *
  237. * Side Effects:
  238. *
  239. *----------------------------------------------------------------------------
  240. */
  241. EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
  242. {
  243. S_SMF_DATA* pSMFData;
  244. EAS_RESULT result;
  245. EAS_I32 i;
  246. EAS_U32 ticks;
  247. EAS_U32 temp;
  248. /* establish pointer to instance data */
  249. pSMFData = (S_SMF_DATA*) pInstData;
  250. if (pSMFData->state >= EAS_STATE_OPEN)
  251. return EAS_SUCCESS;
  252. /* get current ticks */
  253. ticks = pSMFData->nextStream->ticks;
  254. /* assume that an error occurred */
  255. pSMFData->state = EAS_STATE_ERROR;
  256. #ifdef JET_INTERFACE
  257. /* if JET has track muted, set parser mode to mute */
  258. if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE)
  259. parserMode = eParserModeMute;
  260. #endif
  261. /* parse the next event from all the streams */
  262. if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS)
  263. {
  264. /* check for unexpected end-of-file */
  265. if (result != EAS_EOF)
  266. return result;
  267. /* indicate end of track for this stream */
  268. pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
  269. }
  270. /* get next delta time, unless already at end of track */
  271. else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK)
  272. {
  273. if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS)
  274. {
  275. /* check for unexpected end-of-file */
  276. if (result != EAS_EOF)
  277. return result;
  278. /* indicate end of track for this stream */
  279. pSMFData->nextStream->ticks = SMF_END_OF_TRACK;
  280. }
  281. /* if zero delta to next event, stay with this stream */
  282. else if (pSMFData->nextStream->ticks == ticks)
  283. {
  284. pSMFData->state = EAS_STATE_PLAY;
  285. return EAS_SUCCESS;
  286. }
  287. }
  288. /* find next event in all streams */
  289. temp = 0x7ffffff;
  290. pSMFData->nextStream = NULL;
  291. for (i = 0; i < pSMFData->numStreams; i++)
  292. {
  293. if (pSMFData->streams[i].ticks < temp)
  294. {
  295. temp = pSMFData->streams[i].ticks;
  296. pSMFData->nextStream = &pSMFData->streams[i];
  297. }
  298. }
  299. /* are there any more events to parse? */
  300. if (pSMFData->nextStream)
  301. {
  302. pSMFData->state = EAS_STATE_PLAY;
  303. /* update the time of the next event */
  304. SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks);
  305. }
  306. else
  307. {
  308. pSMFData->state = EAS_STATE_STOPPING;
  309. VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
  310. }
  311. return EAS_SUCCESS;
  312. }
  313. /*----------------------------------------------------------------------------
  314. * SMF_State()
  315. *----------------------------------------------------------------------------
  316. * Purpose:
  317. * Returns the current state of the stream
  318. *
  319. * Inputs:
  320. * pEASData - pointer to overall EAS data structure
  321. * handle - pointer to file handle
  322. * pState - pointer to variable to store state
  323. *
  324. * Outputs:
  325. *
  326. *
  327. * Side Effects:
  328. *
  329. *----------------------------------------------------------------------------
  330. */
  331. /*lint -esym(715, pEASData) reserved for future use */
  332. EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
  333. {
  334. S_SMF_DATA* pSMFData;
  335. /* establish pointer to instance data */
  336. pSMFData = (S_SMF_DATA*) pInstData;
  337. /* if stopping, check to see if synth voices are active */
  338. if (pSMFData->state == EAS_STATE_STOPPING)
  339. {
  340. if (VMActiveVoices(pSMFData->pSynth) == 0)
  341. pSMFData->state = EAS_STATE_STOPPED;
  342. }
  343. if (pSMFData->state == EAS_STATE_PAUSING)
  344. {
  345. if (VMActiveVoices(pSMFData->pSynth) == 0)
  346. pSMFData->state = EAS_STATE_PAUSED;
  347. }
  348. /* return current state */
  349. *pState = pSMFData->state;
  350. return EAS_SUCCESS;
  351. }
  352. /*----------------------------------------------------------------------------
  353. * SMF_Close()
  354. *----------------------------------------------------------------------------
  355. * Purpose:
  356. * Close the file and clean up
  357. *
  358. * Inputs:
  359. * pEASData - pointer to overall EAS data structure
  360. * handle - pointer to file handle
  361. *
  362. * Outputs:
  363. *
  364. *
  365. * Side Effects:
  366. *
  367. *----------------------------------------------------------------------------
  368. */
  369. EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
  370. {
  371. S_SMF_DATA* pSMFData;
  372. EAS_I32 i;
  373. EAS_RESULT result;
  374. pSMFData = (S_SMF_DATA*) pInstData;
  375. /* close all the streams */
  376. for (i = 0; i < pSMFData->numStreams; i++)
  377. {
  378. if (pSMFData->streams[i].fileHandle != NULL)
  379. {
  380. if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS)
  381. return result;
  382. }
  383. }
  384. if (pSMFData->fileHandle != NULL)
  385. if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS)
  386. return result;
  387. /* free the synth */
  388. if (pSMFData->pSynth != NULL)
  389. VMMIDIShutdown(pEASData, pSMFData->pSynth);
  390. /* if using dynamic memory, free it */
  391. if (!pEASData->staticMemoryModel)
  392. {
  393. if (pSMFData->streams)
  394. EAS_HWFree(pEASData->hwInstData, pSMFData->streams);
  395. /* free the instance data */
  396. EAS_HWFree(pEASData->hwInstData, pSMFData);
  397. }
  398. return EAS_SUCCESS;
  399. }
  400. /*----------------------------------------------------------------------------
  401. * SMF_Reset()
  402. *----------------------------------------------------------------------------
  403. * Purpose:
  404. * Reset the sequencer. Used for locating backwards in the file.
  405. *
  406. * Inputs:
  407. * pEASData - pointer to overall EAS data structure
  408. * handle - pointer to file handle
  409. *
  410. * Outputs:
  411. *
  412. *
  413. * Side Effects:
  414. *
  415. *----------------------------------------------------------------------------
  416. */
  417. EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
  418. {
  419. S_SMF_DATA* pSMFData;
  420. EAS_I32 i;
  421. EAS_RESULT result;
  422. EAS_U32 ticks;
  423. pSMFData = (S_SMF_DATA*) pInstData;
  424. /* reset time to zero */
  425. pSMFData->time = 0;
  426. /* reset the synth */
  427. VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE);
  428. /* find the start of each track */
  429. ticks = 0x7fffffffL;
  430. pSMFData->nextStream = NULL;
  431. for (i = 0; i < pSMFData->numStreams; i++)
  432. {
  433. /* reset file position to first byte of data in track */
  434. if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS)
  435. return result;
  436. /* initalize some data */
  437. pSMFData->streams[i].ticks = 0;
  438. /* initalize the MIDI parser data */
  439. EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
  440. /* parse the first delta time in each stream */
  441. if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS)
  442. return result;
  443. if (pSMFData->streams[i].ticks < ticks)
  444. {
  445. ticks = pSMFData->streams[i].ticks;
  446. pSMFData->nextStream = &pSMFData->streams[i];
  447. }
  448. }
  449. pSMFData->state = EAS_STATE_READY;
  450. return EAS_SUCCESS;
  451. }
  452. /*----------------------------------------------------------------------------
  453. * SMF_Pause()
  454. *----------------------------------------------------------------------------
  455. * Purpose:
  456. * Pauses the sequencer. Mutes all voices and sets state to pause.
  457. *
  458. * Inputs:
  459. * pEASData - pointer to overall EAS data structure
  460. * handle - pointer to file handle
  461. *
  462. * Outputs:
  463. *
  464. *
  465. * Side Effects:
  466. *
  467. *----------------------------------------------------------------------------
  468. */
  469. EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
  470. {
  471. S_SMF_DATA *pSMFData;
  472. /* can't pause a stopped stream */
  473. pSMFData = (S_SMF_DATA*) pInstData;
  474. if (pSMFData->state == EAS_STATE_STOPPED)
  475. return EAS_ERROR_ALREADY_STOPPED;
  476. /* mute the synthesizer */
  477. VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth);
  478. pSMFData->state = EAS_STATE_PAUSING;
  479. return EAS_SUCCESS;
  480. }
  481. /*----------------------------------------------------------------------------
  482. * SMF_Resume()
  483. *----------------------------------------------------------------------------
  484. * Purpose:
  485. * Resume playing after a pause, sets state back to playing.
  486. *
  487. * Inputs:
  488. * pEASData - pointer to overall EAS data structure
  489. * handle - pointer to file handle
  490. *
  491. * Outputs:
  492. *
  493. *
  494. * Side Effects:
  495. *
  496. *----------------------------------------------------------------------------
  497. */
  498. /*lint -esym(715, pEASData) reserved for future use */
  499. EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
  500. {
  501. S_SMF_DATA *pSMFData;
  502. /* can't resume a stopped stream */
  503. pSMFData = (S_SMF_DATA*) pInstData;
  504. if (pSMFData->state == EAS_STATE_STOPPED)
  505. return EAS_ERROR_ALREADY_STOPPED;
  506. /* nothing to do but resume playback */
  507. pSMFData->state = EAS_STATE_PLAY;
  508. return EAS_SUCCESS;
  509. }
  510. /*----------------------------------------------------------------------------
  511. * SMF_SetData()
  512. *----------------------------------------------------------------------------
  513. * Purpose:
  514. * Sets parser parameters
  515. *
  516. * Inputs:
  517. * pEASData - pointer to overall EAS data structure
  518. * handle - pointer to file handle
  519. *
  520. * Outputs:
  521. *
  522. *
  523. * Side Effects:
  524. *
  525. *----------------------------------------------------------------------------
  526. */
  527. /*lint -esym(715, pEASData) reserved for future use */
  528. EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
  529. {
  530. S_SMF_DATA *pSMFData;
  531. pSMFData = (S_SMF_DATA*) pInstData;
  532. switch (param)
  533. {
  534. /* set metadata callback */
  535. case PARSER_DATA_METADATA_CB:
  536. EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB));
  537. break;
  538. #ifdef JET_INTERFACE
  539. /* set jet segment and track ID of all tracks for callback function */
  540. case PARSER_DATA_JET_CB:
  541. {
  542. EAS_U32 i;
  543. EAS_U32 bit = (EAS_U32) value;
  544. bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK;
  545. for (i = 0; i < pSMFData->numStreams; i++)
  546. pSMFData->streams[i].midiStream.jetData =
  547. (pSMFData->streams[i].midiStream.jetData &
  548. ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) |
  549. i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB;
  550. pSMFData->flags |= SMF_FLAGS_JET_STREAM;
  551. }
  552. break;
  553. /* set state of all mute flags at once */
  554. case PARSER_DATA_MUTE_FLAGS:
  555. {
  556. EAS_INT i;
  557. EAS_U32 bit = (EAS_U32) value;
  558. for (i = 0; i < pSMFData->numStreams; i++)
  559. {
  560. if (bit & 1)
  561. pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
  562. else
  563. pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
  564. bit >>= 1;
  565. }
  566. }
  567. break;
  568. /* set track mute */
  569. case PARSER_DATA_SET_MUTE:
  570. if (value < pSMFData->numStreams)
  571. pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE;
  572. else
  573. return EAS_ERROR_PARAMETER_RANGE;
  574. break;
  575. /* clear track mute */
  576. case PARSER_DATA_CLEAR_MUTE:
  577. if (value < pSMFData->numStreams)
  578. pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE;
  579. else
  580. return EAS_ERROR_PARAMETER_RANGE;
  581. break;
  582. #endif
  583. default:
  584. return EAS_ERROR_INVALID_PARAMETER;
  585. }
  586. return EAS_SUCCESS;
  587. }
  588. /*----------------------------------------------------------------------------
  589. * SMF_GetData()
  590. *----------------------------------------------------------------------------
  591. * Purpose:
  592. * Retrieves parser parameters
  593. *
  594. * Inputs:
  595. * pEASData - pointer to overall EAS data structure
  596. * handle - pointer to file handle
  597. *
  598. * Outputs:
  599. *
  600. *
  601. * Side Effects:
  602. *
  603. *----------------------------------------------------------------------------
  604. */
  605. /*lint -esym(715, pEASData) reserved for future use */
  606. EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
  607. {
  608. S_SMF_DATA *pSMFData;
  609. pSMFData = (S_SMF_DATA*) pInstData;
  610. switch (param)
  611. {
  612. /* return file type */
  613. case PARSER_DATA_FILE_TYPE:
  614. if (pSMFData->numStreams == 1)
  615. *pValue = EAS_FILE_SMF0;
  616. else
  617. *pValue = EAS_FILE_SMF1;
  618. break;
  619. /* now handled in eas_public.c */
  620. #if 0
  621. case PARSER_DATA_POLYPHONY:
  622. if (pSMFData->pSynth)
  623. VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
  624. else
  625. return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
  626. break;
  627. case PARSER_DATA_PRIORITY:
  628. if (pSMFData->pSynth)
  629. VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue);
  630. break;
  631. /* set transposition */
  632. case PARSER_DATA_TRANSPOSITION:
  633. *pValue = pSMFData->transposition;
  634. break;
  635. #endif
  636. case PARSER_DATA_SYNTH_HANDLE:
  637. *pValue = (EAS_I32) pSMFData->pSynth;
  638. break;
  639. default:
  640. return EAS_ERROR_INVALID_PARAMETER;
  641. }
  642. return EAS_SUCCESS;
  643. }
  644. /*----------------------------------------------------------------------------
  645. * SMF_GetVarLenData()
  646. *----------------------------------------------------------------------------
  647. * Purpose:
  648. * Reads a varible length quantity from an SMF file
  649. *
  650. * Inputs:
  651. *
  652. *
  653. * Outputs:
  654. *
  655. *
  656. * Side Effects:
  657. *
  658. *----------------------------------------------------------------------------
  659. */
  660. static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData)
  661. {
  662. EAS_RESULT result;
  663. EAS_U32 data;
  664. EAS_U8 c;
  665. /* read until bit 7 is zero */
  666. data = 0;
  667. do
  668. {
  669. if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS)
  670. return result;
  671. data = (data << 7) | (c & 0x7f);
  672. } while (c & 0x80);
  673. *pData = data;
  674. return EAS_SUCCESS;
  675. }
  676. /*----------------------------------------------------------------------------
  677. * SMF_GetDeltaTime()
  678. *----------------------------------------------------------------------------
  679. * Purpose:
  680. * Reads a varible length quantity from an SMF file
  681. *
  682. * Inputs:
  683. *
  684. *
  685. * Outputs:
  686. *
  687. *
  688. * Side Effects:
  689. *
  690. *----------------------------------------------------------------------------
  691. */
  692. static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream)
  693. {
  694. EAS_RESULT result;
  695. EAS_U32 ticks;
  696. if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS)
  697. return result;
  698. pSMFStream->ticks += ticks;
  699. return EAS_SUCCESS;
  700. }
  701. /*----------------------------------------------------------------------------
  702. * SMF_ParseMetaEvent()
  703. *----------------------------------------------------------------------------
  704. * Purpose:
  705. * Reads a varible length quantity from an SMF file
  706. *
  707. * Inputs:
  708. *
  709. *
  710. * Outputs:
  711. *
  712. *
  713. * Side Effects:
  714. *
  715. *----------------------------------------------------------------------------
  716. */
  717. static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream)
  718. {
  719. EAS_RESULT result;
  720. EAS_U32 len;
  721. EAS_I32 pos;
  722. EAS_U32 temp;
  723. EAS_U8 c;
  724. /* get the meta-event type */
  725. if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
  726. return result;
  727. /* get the length */
  728. if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
  729. return result;
  730. /* get the current file position so we can skip the event */
  731. if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS)
  732. return result;
  733. pos += (EAS_I32) len;
  734. /* end of track? */
  735. if (c == SMF_META_END_OF_TRACK)
  736. {
  737. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ }
  738. pSMFStream->ticks = SMF_END_OF_TRACK;
  739. }
  740. /* tempo event? */
  741. else if (c == SMF_META_TEMPO)
  742. {
  743. /* read the 3-byte timebase value */
  744. temp = 0;
  745. while (len--)
  746. {
  747. if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
  748. return result;
  749. temp = (temp << 8) | c;
  750. }
  751. pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000);
  752. pSMFData->flags |= SMF_FLAGS_HAS_TEMPO;
  753. }
  754. /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */
  755. else if (c == SMF_META_TIME_SIGNATURE)
  756. {
  757. pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG;
  758. }
  759. /* if the host has registered a metadata callback return the metadata */
  760. else if (pSMFData->metadata.callback)
  761. {
  762. EAS_I32 readLen;
  763. E_EAS_METADATA_TYPE metaType;
  764. metaType = EAS_METADATA_UNKNOWN;
  765. /* only process title on the first track */
  766. if (c == SMF_META_SEQTRK_NAME)
  767. metaType = EAS_METADATA_TITLE;
  768. else if (c == SMF_META_TEXT)
  769. metaType = EAS_METADATA_TEXT;
  770. else if (c == SMF_META_COPYRIGHT)
  771. metaType = EAS_METADATA_COPYRIGHT;
  772. else if (c == SMF_META_LYRIC)
  773. metaType = EAS_METADATA_LYRIC;
  774. if (metaType != EAS_METADATA_UNKNOWN)
  775. {
  776. readLen = pSMFData->metadata.bufferSize - 1;
  777. if ((EAS_I32) len < readLen)
  778. readLen = (EAS_I32) len;
  779. if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS)
  780. return result;
  781. pSMFData->metadata.buffer[readLen] = 0;
  782. pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData);
  783. }
  784. }
  785. /* position file to next event - in case we ignored all or part of the meta-event */
  786. if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS)
  787. return result;
  788. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ }
  789. return EAS_SUCCESS;
  790. }
  791. /*----------------------------------------------------------------------------
  792. * SMF_ParseSysEx()
  793. *----------------------------------------------------------------------------
  794. * Purpose:
  795. * Reads a varible length quantity from an SMF file
  796. *
  797. * Inputs:
  798. *
  799. *
  800. * Outputs:
  801. *
  802. *
  803. * Side Effects:
  804. *
  805. *----------------------------------------------------------------------------
  806. */
  807. static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode)
  808. {
  809. EAS_RESULT result;
  810. EAS_U32 len;
  811. EAS_U8 c;
  812. /* get the length */
  813. if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS)
  814. return result;
  815. /* start of SysEx message? */
  816. if (f0 == 0xf0)
  817. {
  818. if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS)
  819. return result;
  820. }
  821. /* feed the SysEx to the stream parser */
  822. while (len--)
  823. {
  824. if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
  825. return result;
  826. if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
  827. return result;
  828. /* check for GM system ON */
  829. if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON)
  830. pSMFData->flags |= SMF_FLAGS_HAS_GM_ON;
  831. }
  832. return EAS_SUCCESS;
  833. }
  834. /*----------------------------------------------------------------------------
  835. * SMF_ParseEvent()
  836. *----------------------------------------------------------------------------
  837. * Purpose:
  838. * Reads a varible length quantity from an SMF file
  839. *
  840. * Inputs:
  841. *
  842. *
  843. * Outputs:
  844. *
  845. *
  846. * Side Effects:
  847. *
  848. *----------------------------------------------------------------------------
  849. */
  850. static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode)
  851. {
  852. EAS_RESULT result;
  853. EAS_U8 c;
  854. /* get the event type */
  855. if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
  856. return result;
  857. /* parse meta-event */
  858. if (c == 0xff)
  859. {
  860. if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS)
  861. return result;
  862. }
  863. /* parse SysEx */
  864. else if ((c == 0xf0) || (c == 0xf7))
  865. {
  866. if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS)
  867. return result;
  868. }
  869. /* parse MIDI message */
  870. else
  871. {
  872. if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
  873. return result;
  874. /* keep streaming data to the MIDI parser until the message is complete */
  875. while (pSMFStream->midiStream.pending)
  876. {
  877. if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS)
  878. return result;
  879. if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS)
  880. return result;
  881. }
  882. }
  883. /* chase mode logic */
  884. if (pSMFData->time == 0)
  885. {
  886. if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
  887. {
  888. if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE)
  889. pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE;
  890. }
  891. else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR)
  892. pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE;
  893. }
  894. return EAS_SUCCESS;
  895. }
  896. /*----------------------------------------------------------------------------
  897. * SMF_ParseHeader()
  898. *----------------------------------------------------------------------------
  899. * Purpose:
  900. * Parses the header of an SMF file, allocates memory the stream parsers and initializes the
  901. * stream parsers.
  902. *
  903. * Inputs:
  904. * pEASData - pointer to overall EAS data structure
  905. * pSMFData - pointer to parser instance data
  906. * fileHandle - file handle
  907. * fileOffset - offset in the file where the header data starts, usually 0
  908. *
  909. *
  910. * Outputs:
  911. *
  912. *
  913. * Side Effects:
  914. *
  915. *----------------------------------------------------------------------------
  916. */
  917. /*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */
  918. EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData)
  919. {
  920. EAS_RESULT result;
  921. EAS_I32 i;
  922. EAS_U16 division;
  923. EAS_U32 chunkSize;
  924. EAS_U32 chunkStart;
  925. EAS_U32 temp;
  926. EAS_U32 ticks;
  927. /* rewind the file and find the end of the header chunk */
  928. if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS)
  929. goto ReadError;
  930. if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
  931. goto ReadError;
  932. /* determine the number of tracks */
  933. if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS)
  934. goto ReadError;
  935. if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS)
  936. goto ReadError;
  937. /* limit the number of tracks */
  938. if (pSMFData->numStreams > MAX_SMF_STREAMS)
  939. {
  940. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ }
  941. pSMFData->numStreams = MAX_SMF_STREAMS;
  942. }
  943. /* get the time division */
  944. if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS)
  945. goto ReadError;
  946. /* setup default timebase for 120 bpm */
  947. pSMFData->ppqn = 192;
  948. if (division & 0x8000)
  949. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ }
  950. else
  951. pSMFData->ppqn = (division & 0x7fff);
  952. pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000);
  953. /* dynamic memory allocation, allocate memory for streams */
  954. if (pSMFData->streams == NULL)
  955. {
  956. pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams);
  957. if (pSMFData->streams == NULL)
  958. return EAS_ERROR_MALLOC_FAILED;
  959. /* zero the memory to insure complete initialization */
  960. EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams);
  961. }
  962. /* find the start of each track */
  963. chunkStart = (EAS_U32) pSMFData->fileOffset;
  964. ticks = 0x7fffffffL;
  965. pSMFData->nextStream = NULL;
  966. for (i = 0; i < pSMFData->numStreams; i++)
  967. {
  968. for (;;)
  969. {
  970. /* calculate start of next chunk - checking for errors */
  971. temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize;
  972. if (temp <= chunkStart)
  973. {
  974. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ }
  975. return EAS_ERROR_FILE_FORMAT;
  976. }
  977. chunkStart = temp;
  978. /* seek to the start of the next chunk */
  979. if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS)
  980. goto ReadError;
  981. /* read the chunk identifier */
  982. if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS)
  983. goto ReadError;
  984. /* read the chunk size */
  985. if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS)
  986. goto ReadError;
  987. /* make sure this is an 'MTrk' chunk */
  988. if (temp == SMF_CHUNK_TYPE_TRACK)
  989. break;
  990. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ }
  991. }
  992. /* initalize some data */
  993. pSMFData->streams[i].ticks = 0;
  994. pSMFData->streams[i].fileHandle = pSMFData->fileHandle;
  995. /* NULL the file handle so we don't try to close it twice */
  996. pSMFData->fileHandle = NULL;
  997. /* save this file position as the start of the track */
  998. pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE;
  999. /* initalize the MIDI parser data */
  1000. EAS_InitMIDIStream(&pSMFData->streams[i].midiStream);
  1001. /* parse the first delta time in each stream */
  1002. if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS)
  1003. goto ReadError;
  1004. if (pSMFData->streams[i].ticks < ticks)
  1005. {
  1006. ticks = pSMFData->streams[i].ticks;
  1007. pSMFData->nextStream = &pSMFData->streams[i];
  1008. }
  1009. /* more tracks to do, create a duplicate file handle */
  1010. if (i < (pSMFData->numStreams - 1))
  1011. {
  1012. if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS)
  1013. goto ReadError;
  1014. }
  1015. }
  1016. /* update the time of the next event */
  1017. if (pSMFData->nextStream)
  1018. SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks);
  1019. return EAS_SUCCESS;
  1020. /* ugly goto: but simpler than structured */
  1021. ReadError:
  1022. if (result == EAS_EOF)
  1023. return EAS_ERROR_FILE_FORMAT;
  1024. return result;
  1025. }
  1026. /*----------------------------------------------------------------------------
  1027. * SMF_UpdateTime()
  1028. *----------------------------------------------------------------------------
  1029. * Purpose:
  1030. * Update the millisecond time base by converting the ticks into millieconds
  1031. *
  1032. * Inputs:
  1033. *
  1034. *
  1035. * Outputs:
  1036. *
  1037. *
  1038. * Side Effects:
  1039. *
  1040. *----------------------------------------------------------------------------
  1041. */
  1042. static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks)
  1043. {
  1044. EAS_U32 temp1, temp2;
  1045. if (pSMFData->flags & SMF_FLAGS_CHASE_MODE)
  1046. return;
  1047. temp1 = (ticks >> 10) * pSMFData->tickConv;
  1048. temp2 = (ticks & 0x3ff) * pSMFData->tickConv;
  1049. pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2));
  1050. }