eas_pcm.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  1. /*----------------------------------------------------------------------------
  2. *
  3. * File:
  4. * eas_pcm.c
  5. *
  6. * Contents and purpose:
  7. * Implements the PCM engine including ADPCM decode for SMAF and CMX audio playback.
  8. *
  9. * Copyright Sonic Network Inc. 2005
  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: 849 $
  25. * $Date: 2007-08-28 08:59:11 -0700 (Tue, 28 Aug 2007) $
  26. *----------------------------------------------------------------------------
  27. */
  28. #include "eas_data.h"
  29. #include "eas_report.h"
  30. #include "eas_host.h"
  31. #include "eas_config.h"
  32. #include "eas_parser.h"
  33. #include "eas_pcm.h"
  34. #include "eas_math.h"
  35. #include "eas_mixer.h"
  36. #define PCM_MIXER_GUARD_BITS (NUM_MIXER_GUARD_BITS + 1)
  37. /*----------------------------------------------------------------------------
  38. * Decoder interfaces
  39. *----------------------------------------------------------------------------
  40. */
  41. static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
  42. static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time);
  43. static const S_DECODER_INTERFACE PCMDecoder =
  44. {
  45. NULL,
  46. LinearPCMDecode,
  47. LinearPCMLocate,
  48. };
  49. /* SMAF ADPCM decoder */
  50. #ifdef _SMAF_PARSER
  51. extern S_DECODER_INTERFACE SmafDecoder;
  52. #define SMAF_DECODER &SmafDecoder
  53. extern S_DECODER_INTERFACE Smaf7BitDecoder;
  54. #define SMAF_7BIT_DECODER &Smaf7BitDecoder
  55. #else
  56. #define SMAF_DECODER NULL
  57. #define SMAF_7BIT_DECODER NULL
  58. #endif
  59. /* IMA ADPCM decoder */
  60. #ifdef _IMA_DECODER
  61. extern S_DECODER_INTERFACE IMADecoder;
  62. #define IMA_DECODER &IMADecoder
  63. #else
  64. #define IMA_DECODER NULL
  65. #endif
  66. static const S_DECODER_INTERFACE * const decoders[] =
  67. {
  68. &PCMDecoder,
  69. SMAF_DECODER,
  70. IMA_DECODER,
  71. SMAF_7BIT_DECODER
  72. };
  73. /*----------------------------------------------------------------------------
  74. * Sample rate conversion
  75. *----------------------------------------------------------------------------
  76. */
  77. #define SRC_RATE_MULTIPLER (0x40000000 / _OUTPUT_SAMPLE_RATE)
  78. #ifdef _LOOKUP_SAMPLE_RATE
  79. static const EAS_U32 srcConvRate[][2] =
  80. {
  81. 4000L, (4000L << 15) / _OUTPUT_SAMPLE_RATE,
  82. 8000L, (8000L << 15) / _OUTPUT_SAMPLE_RATE,
  83. 11025L, (11025L << 15) / _OUTPUT_SAMPLE_RATE,
  84. 12000L, (12000L << 15) / _OUTPUT_SAMPLE_RATE,
  85. 16000L, (16000L << 15) / _OUTPUT_SAMPLE_RATE,
  86. 22050L, (22050L << 15) / _OUTPUT_SAMPLE_RATE,
  87. 24000L, (24000L << 15) / _OUTPUT_SAMPLE_RATE,
  88. 32000L, (32000L << 15) / _OUTPUT_SAMPLE_RATE
  89. };
  90. static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate);
  91. #define SRC_CONV_RATE_ENTRIES (sizeof(srcConvRate)/sizeof(EAS_U32)/2)
  92. #endif
  93. /* interface prototypes */
  94. static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples);
  95. /* local prototypes */
  96. static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData);
  97. static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState);
  98. /*----------------------------------------------------------------------------
  99. * EAS_PEInit()
  100. *----------------------------------------------------------------------------
  101. * Purpose:
  102. * Initializes the PCM engine
  103. *
  104. * Inputs:
  105. *
  106. *
  107. * Outputs:
  108. *
  109. *
  110. * Side Effects:
  111. *
  112. *----------------------------------------------------------------------------
  113. */
  114. EAS_RESULT EAS_PEInit (S_EAS_DATA *pEASData)
  115. {
  116. S_PCM_STATE *pState;
  117. EAS_INT i;
  118. /* check for static memory allocation */
  119. if (pEASData->staticMemoryModel)
  120. pEASData->pPCMStreams = EAS_CMEnumData(EAS_CM_PCM_DATA);
  121. /* allocate dynamic memory */
  122. else
  123. pEASData->pPCMStreams = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS);
  124. if (!pEASData->pPCMStreams)
  125. {
  126. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate memory for PCM streams\n"); */ }
  127. return EAS_ERROR_MALLOC_FAILED;
  128. }
  129. //zero the memory to insure complete initialization
  130. EAS_HWMemSet((void *)(pEASData->pPCMStreams),0, sizeof(S_PCM_STATE) * MAX_PCM_STREAMS);
  131. /* initialize the state data */
  132. for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
  133. pState->fileHandle = NULL;
  134. return EAS_SUCCESS;
  135. }
  136. /*----------------------------------------------------------------------------
  137. * EAS_PEShutdown()
  138. *----------------------------------------------------------------------------
  139. * Purpose:
  140. * Shuts down the PCM engine
  141. *
  142. * Inputs:
  143. *
  144. *
  145. * Outputs:
  146. *
  147. *
  148. * Side Effects:
  149. *
  150. *----------------------------------------------------------------------------
  151. */
  152. EAS_RESULT EAS_PEShutdown (S_EAS_DATA *pEASData)
  153. {
  154. /* free any dynamic memory */
  155. if (!pEASData->staticMemoryModel)
  156. {
  157. if (pEASData->pPCMStreams)
  158. {
  159. EAS_HWFree(pEASData->hwInstData, pEASData->pPCMStreams);
  160. pEASData->pPCMStreams = NULL;
  161. }
  162. }
  163. return EAS_SUCCESS;
  164. }
  165. /*----------------------------------------------------------------------------
  166. * EAS_PERender()
  167. *----------------------------------------------------------------------------
  168. * Purpose:
  169. * Render a buffer of PCM audio
  170. *
  171. * Inputs:
  172. *
  173. *
  174. * Outputs:
  175. *
  176. *
  177. * Side Effects:
  178. *
  179. *----------------------------------------------------------------------------
  180. */
  181. EAS_RESULT EAS_PERender (S_EAS_DATA* pEASData, EAS_I32 numSamples)
  182. {
  183. S_PCM_STATE *pState;
  184. EAS_RESULT result;
  185. EAS_INT i;
  186. /* render all the active streams */
  187. for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
  188. {
  189. if ((pState->fileHandle) && (pState->state != EAS_STATE_STOPPED) && (pState->state != EAS_STATE_PAUSED))
  190. if ((result = RenderPCMStream(pEASData, pState, numSamples)) != EAS_SUCCESS)
  191. return result;
  192. }
  193. return EAS_SUCCESS;
  194. }
  195. /*----------------------------------------------------------------------------
  196. * EAS_PEState()
  197. *----------------------------------------------------------------------------
  198. * Purpose:
  199. * Returns the current state of the stream
  200. *
  201. * Inputs:
  202. * pEASData - pointer to overall EAS data structure
  203. * handle - pointer to file handle
  204. * pState - pointer to variable to store state
  205. *
  206. * Outputs:
  207. *
  208. *
  209. * Side Effects:
  210. *
  211. * Notes:
  212. * This interface is also exposed in the internal library for use by the other modules.
  213. *----------------------------------------------------------------------------
  214. */
  215. /*lint -esym(715, pEASData) reserved for future use */
  216. EAS_RESULT EAS_PEState (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pInstData, EAS_STATE *pState)
  217. {
  218. /* return current state */
  219. *pState = pInstData->state;
  220. return EAS_SUCCESS;
  221. }
  222. /*----------------------------------------------------------------------------
  223. * EAS_PEClose()
  224. *----------------------------------------------------------------------------
  225. * Purpose:
  226. * Close the file and clean up
  227. *
  228. * Inputs:
  229. * pEASData - pointer to overall EAS data structure
  230. * handle - pointer to file handle
  231. *
  232. * Outputs:
  233. *
  234. *
  235. * Side Effects:
  236. *
  237. *----------------------------------------------------------------------------
  238. */
  239. EAS_RESULT EAS_PEClose (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
  240. {
  241. EAS_RESULT result;
  242. if ((result = EAS_HWCloseFile(pEASData->hwInstData, pState->fileHandle)) != EAS_SUCCESS)
  243. return result;
  244. pState->fileHandle = NULL;
  245. return EAS_SUCCESS;
  246. }
  247. /*----------------------------------------------------------------------------
  248. * PCM_Reset()
  249. *----------------------------------------------------------------------------
  250. * Purpose:
  251. * Reset the sequencer. Used for locating backwards in the file.
  252. *
  253. * Inputs:
  254. * pEASData - pointer to overall EAS data structure
  255. * handle - pointer to file handle
  256. *
  257. * Outputs:
  258. *
  259. *
  260. * Side Effects:
  261. *
  262. *----------------------------------------------------------------------------
  263. */
  264. EAS_RESULT EAS_PEReset (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
  265. {
  266. EAS_RESULT result;
  267. /* reset file position to first byte of data in the stream */
  268. if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS)
  269. {
  270. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %d seeking to start of PCM file\n", result); */ }
  271. return result;
  272. }
  273. /* re-initialize stream */
  274. return InitPCMStream(pEASData, pState);
  275. }
  276. /*----------------------------------------------------------------------------
  277. * EAS_PEOpenStream()
  278. *----------------------------------------------------------------------------
  279. * Purpose:
  280. * Starts up a PCM playback
  281. *
  282. * Inputs:
  283. *
  284. *
  285. * Outputs:
  286. *
  287. *
  288. * Side Effects:
  289. *
  290. *----------------------------------------------------------------------------
  291. */
  292. EAS_RESULT EAS_PEOpenStream (S_EAS_DATA *pEASData, S_PCM_OPEN_PARAMS *pParams, EAS_PCM_HANDLE *pHandle)
  293. {
  294. EAS_RESULT result;
  295. S_PCM_STATE *pState;
  296. EAS_I32 filePos;
  297. /* make sure we support this decoder */
  298. if (pParams->decoder >= NUM_DECODER_MODULES)
  299. {
  300. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder selector out of range\n"); */ }
  301. return EAS_ERROR_PARAMETER_RANGE;
  302. }
  303. if (decoders[pParams->decoder] == NULL)
  304. {
  305. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Decoder module not available\n"); */ }
  306. return EAS_ERROR_FEATURE_NOT_AVAILABLE;
  307. }
  308. /* find a slot for the new stream */
  309. if ((pState = FindSlot(pEASData, pParams->fileHandle, pParams->pCallbackFunc, pParams->cbInstData)) == NULL)
  310. {
  311. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to open ADPCM stream, too many streams open\n"); */ }
  312. return EAS_ERROR_MAX_PCM_STREAMS;
  313. }
  314. /* get the current file position */
  315. if ((result = EAS_HWFilePos(pEASData->hwInstData, pState->fileHandle, &filePos)) != EAS_SUCCESS)
  316. {
  317. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_HWFilePos returned %ld\n",result); */ }
  318. pState->fileHandle = NULL;
  319. return result;
  320. }
  321. pState->pDecoder = decoders[pParams->decoder];
  322. pState->startPos = filePos;
  323. pState->bytesLeftLoop = pState->byteCount = pParams->size;
  324. pState->loopStart = pParams->loopStart;
  325. pState->samplesTilLoop = (EAS_I32) pState->loopStart;
  326. pState->loopSamples = pParams->loopSamples;
  327. pState->samplesInLoop = 0;
  328. pState->blockSize = (EAS_U16) pParams->blockSize;
  329. pState->flags = pParams->flags;
  330. pState->envData = pParams->envData;
  331. pState->volume = pParams->volume;
  332. pState->sampleRate = (EAS_U16) pParams->sampleRate;
  333. /* set the base frequency */
  334. pState->basefreq = (SRC_RATE_MULTIPLER * (EAS_U32) pParams->sampleRate) >> 15;
  335. /* calculate shift for frequencies > 1.0 */
  336. pState->rateShift = 0;
  337. while (pState->basefreq > 32767)
  338. {
  339. pState->basefreq = pState->basefreq >> 1;
  340. pState->rateShift++;
  341. }
  342. /* initialize */
  343. if ((result = InitPCMStream(pEASData, pState)) != EAS_SUCCESS)
  344. return result;
  345. *pHandle = pState;
  346. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PEOpenStream: StartPos=%d, byteCount = %d, loopSamples=%d\n",
  347. pState->startPos, pState->byteCount, pState->loopSamples); */ }
  348. return EAS_SUCCESS;
  349. }
  350. /*----------------------------------------------------------------------------
  351. * EAS_PEContinueStream()
  352. *----------------------------------------------------------------------------
  353. * Purpose:
  354. * Continues a PCM stream
  355. *
  356. * Inputs:
  357. *
  358. *
  359. * Outputs:
  360. *
  361. *
  362. * Side Effects:
  363. *
  364. *----------------------------------------------------------------------------
  365. */
  366. /*lint -e{715} reserved for future use */
  367. EAS_RESULT EAS_PEContinueStream (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 size)
  368. {
  369. /* add new samples to count */
  370. pState->bytesLeft += size;
  371. if (pState->bytesLeft > 0)
  372. pState->flags &= ~PCM_FLAGS_EMPTY;
  373. return EAS_SUCCESS;
  374. }
  375. /*----------------------------------------------------------------------------
  376. * EAS_PEGetFileHandle()
  377. *----------------------------------------------------------------------------
  378. * Purpose:
  379. * Returns the file handle of a stream
  380. *
  381. * Inputs:
  382. *
  383. *
  384. * Outputs:
  385. *
  386. *
  387. * Side Effects:
  388. *
  389. *----------------------------------------------------------------------------
  390. */
  391. /*lint -esym(715, pEASData) reserved for future use */
  392. EAS_RESULT EAS_PEGetFileHandle (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_FILE_HANDLE *pFileHandle)
  393. {
  394. *pFileHandle = pState->fileHandle;
  395. return EAS_SUCCESS;
  396. }
  397. /*----------------------------------------------------------------------------
  398. * EAS_PEUpdateParams()
  399. *----------------------------------------------------------------------------
  400. * Purpose:
  401. * Update the pitch and volume parameters for a PCM stream
  402. *
  403. * Inputs:
  404. * pEASData - pointer to EAS library instance data
  405. * handle - pointer to S_PCM_STATE for this stream
  406. * gainLeft - linear gain multipler in 1.15 fraction format
  407. * gainRight - linear gain multipler in 1.15 fraction format
  408. * pitch - pitch shift in cents
  409. * initial - initial settings, set current gain
  410. *
  411. * Outputs:
  412. *
  413. *
  414. * Side Effects:
  415. *
  416. * Notes
  417. * In mono mode, leftGain controls the output gain and rightGain is ignored
  418. *----------------------------------------------------------------------------
  419. */
  420. /*lint -esym(715, pEASData) reserved for future use */
  421. /*lint -esym(715, gainRight) used only in 2-channel version */
  422. EAS_RESULT EAS_PEUpdateParams (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch, EAS_I16 gainLeft, EAS_I16 gainRight)
  423. {
  424. pState->gainLeft = gainLeft;
  425. #if (NUM_OUTPUT_CHANNELS == 2)
  426. pState->gainRight = gainRight;
  427. #endif
  428. pState->pitch = pitch;
  429. return EAS_SUCCESS;
  430. }
  431. /*----------------------------------------------------------------------------
  432. * EAS_PELocate()
  433. *----------------------------------------------------------------------------
  434. * Purpose:
  435. * This function seeks to the requested place in the file. Accuracy
  436. * is dependent on the sample rate and block size.
  437. *
  438. * Inputs:
  439. * pEASData - pointer to overall EAS data structure
  440. * pState - stream handle
  441. * time - media time in milliseconds
  442. *----------------------------------------------------------------------------
  443. */
  444. EAS_RESULT EAS_PELocate (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState, EAS_I32 time)
  445. {
  446. if (pState->pDecoder->pfLocate == NULL)
  447. return EAS_ERROR_FEATURE_NOT_AVAILABLE;
  448. return pState->pDecoder->pfLocate(pEASData, pState, time);
  449. }
  450. /*----------------------------------------------------------------------------
  451. * EAS_PEUpdateVolume()
  452. *----------------------------------------------------------------------------
  453. * Purpose:
  454. * Update the volume parameters for a PCM stream
  455. *
  456. * Inputs:
  457. * pEASData - pointer to EAS library instance data
  458. * handle - pointer to S_PCM_STATE for this stream
  459. * gainLeft - linear gain multipler in 1.15 fraction format
  460. * gainRight - linear gain multipler in 1.15 fraction format
  461. * initial - initial settings, set current gain
  462. *
  463. * Outputs:
  464. *
  465. *
  466. * Side Effects:
  467. *
  468. * Notes
  469. * In mono mode, leftGain controls the output gain and rightGain is ignored
  470. *----------------------------------------------------------------------------
  471. */
  472. /*lint -esym(715, pEASData) reserved for future use */
  473. EAS_RESULT EAS_PEUpdateVolume (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 volume)
  474. {
  475. pState->volume = volume;
  476. return EAS_SUCCESS;
  477. }
  478. /*----------------------------------------------------------------------------
  479. * EAS_PEUpdatePitch()
  480. *----------------------------------------------------------------------------
  481. * Purpose:
  482. * Update the pitch parameter for a PCM stream
  483. *
  484. * Inputs:
  485. * pEASData - pointer to EAS library instance data
  486. * pState - pointer to S_PCM_STATE for this stream
  487. * pitch - new pitch value in pitch cents
  488. *----------------------------------------------------------------------------
  489. */
  490. /*lint -esym(715, pEASData) reserved for future use */
  491. EAS_RESULT EAS_PEUpdatePitch (S_EAS_DATA* pEASData, EAS_PCM_HANDLE pState, EAS_I16 pitch)
  492. {
  493. pState->pitch = pitch;
  494. return EAS_SUCCESS;
  495. }
  496. /*----------------------------------------------------------------------------
  497. * EAS_PEPause()
  498. *----------------------------------------------------------------------------
  499. * Purpose:
  500. * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback
  501. * at the end of the next audio frame.
  502. *
  503. * Inputs:
  504. * pEASData - pointer to EAS library instance data
  505. * handle - pointer to S_PCM_STATE for this stream
  506. *
  507. * Outputs:
  508. *
  509. *
  510. * Side Effects:
  511. *
  512. *----------------------------------------------------------------------------
  513. */
  514. /*lint -esym(715, pEASData) reserved for future use */
  515. EAS_RESULT EAS_PEPause (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
  516. {
  517. /* set state to stopping */
  518. pState->state = EAS_STATE_PAUSING;
  519. return EAS_SUCCESS;
  520. }
  521. /*----------------------------------------------------------------------------
  522. * EAS_PEResume()
  523. *----------------------------------------------------------------------------
  524. * Purpose:
  525. * Resume rendering a PCM stream. Sets the gain target back to its
  526. * previous setting and restarts playback at the end of the next audio
  527. * frame.
  528. *
  529. * Inputs:
  530. * pEASData - pointer to EAS library instance data
  531. * handle - pointer to S_PCM_STATE for this stream
  532. *
  533. * Outputs:
  534. *
  535. *
  536. * Side Effects:
  537. *
  538. *----------------------------------------------------------------------------
  539. */
  540. /*lint -esym(715, pEASData) reserved for future use */
  541. EAS_RESULT EAS_PEResume (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
  542. {
  543. /* set state to stopping */
  544. pState->state = EAS_STATE_PLAY;
  545. return EAS_SUCCESS;
  546. }
  547. EAS_U32 getDecayScale(EAS_U32 index)
  548. {
  549. EAS_U32 utemp;
  550. //envelope decay segment
  551. switch (index)
  552. {
  553. case 0: //no decay
  554. utemp = 512;//32768;
  555. break;
  556. case 1: //.0156 dB per update
  557. utemp = 511;//32709;
  558. break;
  559. case 2: //.03125
  560. utemp = 510;//32649;
  561. break;
  562. case 3: //.0625
  563. utemp = 508;//32532;
  564. break;
  565. case 4: //.125
  566. utemp = 505;//32298;
  567. break;
  568. case 5: //.25
  569. utemp = 497;//31835;
  570. break;
  571. case 6: //.5
  572. utemp = 483;//30929;
  573. break;
  574. case 7: //1.0
  575. utemp = 456;//29193;
  576. break;
  577. case 8: //2.0
  578. utemp = 406;//26008;
  579. break;
  580. case 9: //4.0
  581. utemp = 323;//20642;
  582. break;
  583. case 10: //8.0
  584. utemp = 203;//13004;
  585. break;
  586. case 11: //16.0
  587. utemp = 81;//5160;
  588. break;
  589. case 12: //32.0
  590. utemp = 13;//813;
  591. break;
  592. case 13: //64.0
  593. utemp = 0;//20;
  594. break;
  595. case 14: //128.0
  596. utemp = 0;
  597. break;
  598. case 15: //256.0
  599. default:
  600. utemp = 0;
  601. break;
  602. }
  603. //printf("getdecayscale returned %d\n",utemp);
  604. return utemp;
  605. }
  606. EAS_U32 getAttackIncrement(EAS_U32 index)
  607. {
  608. EAS_U32 utemp;
  609. //envelope decay segment
  610. switch (index)
  611. {
  612. case 0:
  613. utemp = 32;
  614. break;
  615. case 1:
  616. utemp = 64;
  617. break;
  618. case 2:
  619. utemp = 128;
  620. break;
  621. case 3:
  622. utemp = 256;
  623. break;
  624. case 4:
  625. utemp = 512;
  626. break;
  627. case 5:
  628. utemp = 1024;
  629. break;
  630. case 6:
  631. utemp = 2048;
  632. break;
  633. case 7:
  634. utemp = 4096;
  635. break;
  636. case 8:
  637. utemp = 8192;
  638. break;
  639. case 9:
  640. utemp = 16384;
  641. break;
  642. case 10:
  643. utemp = 32768;
  644. break;
  645. case 11:
  646. utemp = 65536;
  647. break;
  648. case 12:
  649. utemp = 65536;
  650. break;
  651. case 13:
  652. utemp = 65536;
  653. break;
  654. case 14:
  655. utemp = 65535;
  656. break;
  657. case 15:
  658. default:
  659. utemp = 0;
  660. break;
  661. }
  662. //printf("getattackincrement returned %d\n",utemp);
  663. return utemp;
  664. }
  665. /*----------------------------------------------------------------------------
  666. * EAS_PERelease()
  667. *----------------------------------------------------------------------------
  668. * Purpose:
  669. * Put the PCM stream envelope into release.
  670. *
  671. * Inputs:
  672. * pEASData - pointer to EAS library instance data
  673. * handle - pointer to S_PCM_STATE for this stream
  674. *
  675. * Outputs:
  676. *
  677. *
  678. * Side Effects:
  679. *
  680. *----------------------------------------------------------------------------
  681. */
  682. /*lint -esym(715, pEASData) reserved for future use */
  683. EAS_RESULT EAS_PERelease (S_EAS_DATA *pEASData, EAS_PCM_HANDLE pState)
  684. {
  685. EAS_U32 utemp;
  686. //printf("handling note-off part of envelope\n");
  687. /*if the note is not ignore release or sustained*/
  688. if (((pState->envData >> 24) & 0x0F)==0)
  689. {
  690. /* set envelope state to release */
  691. pState->envState = PCM_ENV_RELEASE;
  692. utemp = ((pState->envData >> 20) & 0x0F);
  693. pState->envScale = getDecayScale(utemp); //getReleaseScale(utemp);
  694. }
  695. else
  696. {
  697. /*else change envelope state to sustain */
  698. pState->envState = PCM_ENV_SUSTAIN;
  699. utemp = ((pState->envData >> 28) & 0x0F);
  700. pState->envScale = getDecayScale(utemp); //getSustainScale(utemp);
  701. }
  702. //since we are in release, don't let anything hang around too long
  703. //printf("checking env scale, val = %d\n",((S_PCM_STATE*) handle)->envScale);
  704. if (pState->envScale > 505)
  705. pState->envScale = 505;
  706. return EAS_SUCCESS;
  707. }
  708. /*----------------------------------------------------------------------------
  709. * FindSlot()
  710. *----------------------------------------------------------------------------
  711. * Purpose:
  712. * Locates an empty stream slot and assigns the file handle
  713. *
  714. * Inputs:
  715. * pEASData - pointer to EAS library instance data
  716. * fileHandle - file handle
  717. * pCallbackFunc - function to be called back upon EAS_STATE_STOPPED
  718. *
  719. * Outputs:
  720. * returns handle to slot or NULL if all slots are used
  721. *
  722. * Side Effects:
  723. *
  724. *----------------------------------------------------------------------------
  725. */
  726. static S_PCM_STATE *FindSlot (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_PCM_CALLBACK pCallbackFunc, EAS_VOID_PTR cbInstData)
  727. {
  728. EAS_INT i;
  729. S_PCM_STATE *pState;
  730. #ifndef NO_PCM_STEAL
  731. S_PCM_STATE *foundState = NULL;
  732. EAS_INT count = 0;
  733. EAS_U32 startOrder = 0xFFFFFFFF;
  734. S_PCM_STATE *stealState = NULL;
  735. EAS_U32 youngest = 0;
  736. /* find an empty slot, count total in use, and find oldest in use (lowest start order) */
  737. for (i = 0, pState = pEASData->pPCMStreams; i < MAX_PCM_STREAMS; i++, pState++)
  738. {
  739. /* if this one is available */
  740. if (pState->fileHandle == NULL)
  741. {
  742. foundState = pState;
  743. }
  744. /* else this one is in use, so see if it is the oldest, and count total in use */
  745. /* also find youngest */
  746. else
  747. {
  748. /*one more voice in use*/
  749. count++;
  750. /* is this the oldest? (lowest start order) */
  751. if ((pState->state != EAS_STATE_STOPPING) && (pState->startOrder < startOrder))
  752. {
  753. /* remember this one */
  754. stealState = pState;
  755. /* remember the oldest so far */
  756. startOrder = pState->startOrder;
  757. }
  758. /* is this the youngest? (highest start order) */
  759. if (pState->startOrder >= youngest)
  760. {
  761. youngest = pState->startOrder;
  762. }
  763. }
  764. }
  765. /* if there are too many voices active, stop the oldest one */
  766. if (count > PCM_STREAM_THRESHOLD)
  767. {
  768. //printf("stealing!!!\n");
  769. /* make sure we got one, although we should always have one at this point */
  770. if (stealState != NULL)
  771. {
  772. //flag this as stopping, so it will get shut off
  773. stealState->state = EAS_STATE_STOPPING;
  774. }
  775. }
  776. /* if there are no available open streams (we won't likely see this, due to stealing) */
  777. if (foundState == NULL)
  778. return NULL;
  779. /* save info */
  780. foundState->startOrder = youngest + 1;
  781. foundState->fileHandle = fileHandle;
  782. foundState->pCallback = pCallbackFunc;
  783. foundState->cbInstData = cbInstData;
  784. return foundState;
  785. #else
  786. /* find an empty slot*/
  787. for (i = 0; i < MAX_PCM_STREAMS; i++)
  788. {
  789. pState = &pEASData->pPCMStreams[i];
  790. if (pState->fileHandle != NULL)
  791. continue;
  792. pState->fileHandle = fileHandle;
  793. pState->pCallback = pCallbackFunc;
  794. pState->cbInstData = cbInstData;
  795. return pState;
  796. }
  797. return NULL;
  798. #endif
  799. }
  800. #ifdef _LOOKUP_SAMPLE_RATE
  801. /*----------------------------------------------------------------------------
  802. * CalcBaseFreq()
  803. *----------------------------------------------------------------------------
  804. * Purpose:
  805. * Calculates the fractional phase increment for the sample rate converter
  806. *
  807. * Inputs:
  808. * sampleRate - sample rate in samples/sec
  809. *
  810. * Outputs:
  811. * Returns fractional sample rate with a 15-bit fraction
  812. *
  813. * Side Effects:
  814. *
  815. *----------------------------------------------------------------------------
  816. */
  817. static EAS_U32 CalcBaseFreq (EAS_U32 sampleRate)
  818. {
  819. EAS_INT i;
  820. /* look up the conversion rate */
  821. for (i = 0; i < (EAS_INT)(SRC_CONV_RATE_ENTRIES); i ++)
  822. {
  823. if (srcConvRate[i][0] == sampleRate)
  824. return srcConvRate[i][1];
  825. }
  826. /* if not found in table, do it the long way */
  827. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Sample rate %u not in table, calculating by division\n", sampleRate); */ }
  828. return (SRC_RATE_MULTIPLER * (EAS_U32) sampleRate) >> 15;
  829. }
  830. #endif
  831. /*----------------------------------------------------------------------------
  832. * InitPCMStream()
  833. *----------------------------------------------------------------------------
  834. * Purpose:
  835. * Start an ADPCM stream playback. Decodes the header, preps the engine.
  836. *
  837. * Inputs:
  838. *
  839. *
  840. * Outputs:
  841. *
  842. *
  843. * Side Effects:
  844. *
  845. *----------------------------------------------------------------------------
  846. */
  847. static EAS_RESULT InitPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState)
  848. {
  849. /* initialize the data structure */
  850. pState->bytesLeft = pState->byteCount;
  851. pState->phase = 0;
  852. pState->srcByte = 0;
  853. pState->decoderL.acc = 0;
  854. pState->decoderL.output = 0;
  855. pState->decoderL.x0 = pState->decoderL.x1 = 0;
  856. pState->decoderL.step = 0;
  857. pState->decoderR.acc = 0;
  858. pState->decoderR.output = 0;
  859. pState->decoderR.x0 = pState->decoderR.x1 = 0;
  860. pState->decoderR.step = 0;
  861. pState->hiNibble = EAS_FALSE;
  862. pState->pitch = 0;
  863. pState->blockCount = 0;
  864. pState->gainLeft = PCM_DEFAULT_GAIN_SETTING;
  865. // pState->currentGainLeft = PCM_DEFAULT_GAIN_SETTING;
  866. pState->envValue = 0;
  867. pState->envState = PCM_ENV_START;
  868. #if (NUM_OUTPUT_CHANNELS == 2)
  869. pState->gainRight = PCM_DEFAULT_GAIN_SETTING;
  870. // pState->currentGainRight = PCM_DEFAULT_GAIN_SETTING;
  871. #endif
  872. pState->state = EAS_STATE_READY;
  873. /* initialize the decoder */
  874. if (pState->pDecoder->pfInit)
  875. return (*pState->pDecoder->pfInit)(pEASData, pState);
  876. return EAS_SUCCESS;
  877. }
  878. /*----------------------------------------------------------------------------
  879. * RenderPCMStream()
  880. *----------------------------------------------------------------------------
  881. * Purpose:
  882. * Decodes a buffer of ADPCM data.
  883. *
  884. * Inputs:
  885. *
  886. *
  887. * Outputs:
  888. *
  889. *
  890. * Side Effects:
  891. *
  892. *----------------------------------------------------------------------------
  893. */
  894. static EAS_RESULT RenderPCMStream (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 numSamples)
  895. {
  896. EAS_RESULT result;
  897. EAS_U32 phaseInc;
  898. EAS_I32 gainLeft, gainIncLeft;
  899. EAS_I32 *pOut;
  900. EAS_I32 temp;
  901. EAS_U32 utemp;
  902. #if (NUM_OUTPUT_CHANNELS == 2)
  903. EAS_I32 gainRight, gainIncRight;
  904. #endif
  905. #if 0
  906. printf("env data: AR = %d, DR = %d, SL = %d, SR = %d, RR = %d\n",
  907. ((pState->envData >> 12) & 0x0F),
  908. ((pState->envData >> 16) & 0x0F),
  909. ((pState->envData >> 8) & 0x0F),
  910. ((pState->envData >> 28) & 0x0F),
  911. ((pState->envData >> 20) & 0x0F));
  912. #endif
  913. if (pState->envState == PCM_ENV_START)
  914. {
  915. //printf("env start\n");
  916. utemp = ((pState->envData >> 12) & 0x0F);
  917. //if fastest rate, attack is already completed
  918. //do the same for slowest rate, since that allows zero to be passed for default envelope
  919. if (utemp == 0x0F || utemp == 0x00)
  920. {
  921. //start envelope at full
  922. pState->envValue = (32768<<7);
  923. //jump right into decay
  924. utemp = ((pState->envData >> 16) & 0x0F);
  925. pState->envScale = getDecayScale(utemp);
  926. pState->envState = PCM_ENV_DECAY;
  927. pState->currentGainLeft = (EAS_I16) FMUL_15x15(pState->gainLeft, pState->volume);
  928. pState->currentGainRight = (EAS_I16) FMUL_15x15(pState->gainRight, pState->volume);
  929. }
  930. //else attack has a ramp
  931. else
  932. {
  933. //start the envelope very low
  934. pState->envValue = (2<<7);
  935. pState->currentGainLeft = 0;
  936. pState->currentGainRight = 0;
  937. //get envelope attack scaling value
  938. pState->envScale = getAttackIncrement(utemp);
  939. //go to attack state
  940. pState->envState = PCM_ENV_ATTACK;
  941. }
  942. }
  943. if (pState->envState == PCM_ENV_ATTACK)
  944. {
  945. //printf("env attack, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
  946. //update envelope value
  947. pState->envValue = pState->envValue + (pState->envScale << 7);
  948. //check envelope level and update state if needed
  949. if (pState->envValue >= (32768<<7))
  950. {
  951. pState->envValue = (32768<<7);
  952. utemp = ((pState->envData >> 16) & 0x0F);
  953. pState->envScale = getDecayScale(utemp);
  954. pState->envState = PCM_ENV_DECAY;
  955. }
  956. }
  957. else if (pState->envState == PCM_ENV_DECAY)
  958. {
  959. //printf("env decay, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
  960. //update envelope value
  961. pState->envValue = (pState->envValue * pState->envScale)>>9;
  962. //check envelope level against sustain level and update state if needed
  963. utemp = ((pState->envData >> 8) & 0x0F);
  964. if (utemp == (EAS_U32)0x0F)
  965. utemp = (2<<7);
  966. else
  967. {
  968. utemp = ((32769<<7) >> (utemp>>1));
  969. }
  970. if (pState->envValue <= utemp)
  971. {
  972. utemp = ((pState->envData >> 28) & 0x0F);
  973. pState->envScale = getDecayScale(utemp); //getSustainScale(utemp);
  974. pState->envState = PCM_ENV_SUSTAIN;
  975. }
  976. }
  977. else if (pState->envState == PCM_ENV_SUSTAIN)
  978. {
  979. //printf("env sustain, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
  980. //update envelope value
  981. pState->envValue = (pState->envValue * pState->envScale)>>9;
  982. //check envelope level against bottom level and update state if needed
  983. if (pState->envValue <= (2<<7))
  984. {
  985. //no more decay
  986. pState->envScale = 512;
  987. pState->envState = PCM_ENV_END;
  988. }
  989. }
  990. else if (pState->envState == PCM_ENV_RELEASE)
  991. {
  992. //printf("env release, env value = %d, env scale = %d\n",pState->envValue>>7,pState->envScale);
  993. //update envelope value
  994. pState->envValue = (pState->envValue * pState->envScale)>>9;
  995. //check envelope level against bottom level and update state if needed
  996. if (pState->envValue <= (2<<7))
  997. {
  998. //no more decay
  999. pState->envScale = 512;
  1000. pState->envState = PCM_ENV_END;
  1001. }
  1002. }
  1003. else if (pState->envState == PCM_ENV_END)
  1004. {
  1005. //printf("env end\n");
  1006. /* set state to stopping, already ramped down */
  1007. pState->state = EAS_STATE_STOPPING;
  1008. }
  1009. //pState->gainLeft = (EAS_U16)((pState->gainLeft * (pState->envValue>>7))>>15);
  1010. //pState->gainRight = (EAS_U16)((pState->gainRight * (pState->envValue>>7))>>15);
  1011. /* gain to 32-bits to increase resolution on anti-zipper filter */
  1012. /*lint -e{703} use shift for performance */
  1013. gainLeft = (EAS_I32) pState->currentGainLeft << SYNTH_UPDATE_PERIOD_IN_BITS;
  1014. #if (NUM_OUTPUT_CHANNELS == 2)
  1015. /*lint -e{703} use shift for performance */
  1016. gainRight = (EAS_I32) pState->currentGainRight << SYNTH_UPDATE_PERIOD_IN_BITS;
  1017. #endif
  1018. /* calculate a new gain increment, gain target is zero if pausing */
  1019. if ((pState->state == EAS_STATE_PAUSING) || (pState->state == EAS_STATE_PAUSED))
  1020. {
  1021. gainIncLeft = -pState->currentGainLeft;
  1022. #if (NUM_OUTPUT_CHANNELS == 2)
  1023. gainIncRight= -pState->currentGainRight;
  1024. #endif
  1025. }
  1026. else
  1027. {
  1028. EAS_I32 gain = FMUL_15x15(pState->envValue >> 7, pState->volume);
  1029. gainIncLeft = FMUL_15x15(pState->gainLeft, gain) - pState->currentGainLeft;
  1030. #if (NUM_OUTPUT_CHANNELS == 2)
  1031. gainIncRight = FMUL_15x15(pState->gainRight, gain) - pState->currentGainRight;
  1032. #endif
  1033. }
  1034. /* calculate phase increment */
  1035. phaseInc = pState->basefreq;
  1036. /* convert pitch cents to linear multiplier */
  1037. if (pState->pitch)
  1038. {
  1039. temp = EAS_Calculate2toX(pState->pitch);
  1040. phaseInc = FMUL_15x15(phaseInc, temp);
  1041. }
  1042. phaseInc = phaseInc << pState->rateShift;
  1043. /* pointer to mix buffer */
  1044. pOut = pEASData->pMixBuffer;
  1045. /* render a buffer of samples */
  1046. while (numSamples--)
  1047. {
  1048. /* interpolate an output sample */
  1049. pState->decoderL.output = pState->decoderL.x0 + FMUL_15x15((pState->decoderL.x1 - pState->decoderL.x0), pState->phase & PHASE_FRAC_MASK);
  1050. /* stereo output */
  1051. #if (NUM_OUTPUT_CHANNELS == 2)
  1052. /* stereo stream? */
  1053. if (pState->flags & PCM_FLAGS_STEREO)
  1054. pState->decoderR.output = pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK);
  1055. /* gain scale and mix */
  1056. /*lint -e{704} use shift instead of division */
  1057. *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
  1058. gainLeft += gainIncLeft;
  1059. /*lint -e{704} use shift instead of division */
  1060. if (pState->flags & PCM_FLAGS_STEREO)
  1061. *pOut++ += (pState->decoderR.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
  1062. else
  1063. *pOut++ += (pState->decoderL.output * (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
  1064. gainRight += gainIncRight;
  1065. /* mono output */
  1066. #else
  1067. /* if stereo stream, decode right channel and mix to mono */
  1068. if (pState->flags & PCM_FLAGS_STEREO)
  1069. {
  1070. pState->decoderR.output= pState->decoderR.x0 + FMUL_15x15((pState->decoderR.x1 - pState->decoderR.x0), pState->phase & PHASE_FRAC_MASK);
  1071. /* for mono, sum stereo ADPCM to mono */
  1072. /*lint -e{704} use shift instead of division */
  1073. *pOut++ += ((pState->decoderL.output + pState->decoderR.output) * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
  1074. }
  1075. else
  1076. /*lint -e{704} use shift instead of division */
  1077. *pOut++ += (pState->decoderL.output * (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS)) >> PCM_MIXER_GUARD_BITS;
  1078. gainLeft += gainIncLeft;
  1079. #endif
  1080. /* advance phase accumulator */
  1081. pState->phase += phaseInc;
  1082. /* if integer part of phase accumulator is non-zero, advance to next sample */
  1083. while (pState->phase & ~PHASE_FRAC_MASK)
  1084. {
  1085. pState->decoderL.x0 = pState->decoderL.x1;
  1086. pState->decoderR.x0 = pState->decoderR.x1;
  1087. /* give the source a chance to continue the stream */
  1088. if (!pState->bytesLeft && pState->pCallback && ((pState->flags & PCM_FLAGS_EMPTY) == 0))
  1089. {
  1090. pState->flags |= PCM_FLAGS_EMPTY;
  1091. (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY);
  1092. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "RenderPCMStream: After empty callback, bytesLeft = %d\n", pState->bytesLeft); */ }
  1093. }
  1094. /* decode the next sample */
  1095. if ((result = (*pState->pDecoder->pfDecodeSample)(pEASData, pState)) != EAS_SUCCESS)
  1096. return result;
  1097. /* adjust phase by one sample */
  1098. pState->phase -= (1L << NUM_PHASE_FRAC_BITS);
  1099. }
  1100. }
  1101. /* save new gain */
  1102. /*lint -e{704} use shift instead of division */
  1103. pState->currentGainLeft = (EAS_I16) (gainLeft >> SYNTH_UPDATE_PERIOD_IN_BITS);
  1104. #if (NUM_OUTPUT_CHANNELS == 2)
  1105. /*lint -e{704} use shift instead of division */
  1106. pState->currentGainRight = (EAS_I16) (gainRight >> SYNTH_UPDATE_PERIOD_IN_BITS);
  1107. #endif
  1108. /* if pausing, set new state and notify */
  1109. if (pState->state == EAS_STATE_PAUSING)
  1110. {
  1111. pState->state = EAS_STATE_PAUSED;
  1112. if (pState->pCallback)
  1113. (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state);
  1114. }
  1115. /* if out of data, set stopped state and notify */
  1116. if (pState->bytesLeft == 0 || pState->state == EAS_STATE_STOPPING)
  1117. {
  1118. pState->state = EAS_STATE_STOPPED;
  1119. /* do callback unless the file has already been closed */
  1120. if (pState->pCallback && pState->fileHandle)
  1121. (*pState->pCallback)(pEASData, pState->cbInstData, pState, pState->state);
  1122. }
  1123. if (pState->state == EAS_STATE_READY)
  1124. pState->state = EAS_STATE_PLAY;
  1125. return EAS_SUCCESS;
  1126. }
  1127. /*----------------------------------------------------------------------------
  1128. * LinearPCMDecode()
  1129. *----------------------------------------------------------------------------
  1130. * Purpose:
  1131. * Decodes a PCM sample
  1132. *
  1133. * Inputs:
  1134. *
  1135. *
  1136. * Outputs:
  1137. *
  1138. *
  1139. * Side Effects:
  1140. *
  1141. *----------------------------------------------------------------------------
  1142. */
  1143. static EAS_RESULT LinearPCMDecode (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
  1144. {
  1145. EAS_RESULT result;
  1146. EAS_HW_DATA_HANDLE hwInstData;
  1147. hwInstData = ((S_EAS_DATA*) pEASData)->hwInstData;
  1148. /* if out of data, check for loop */
  1149. if ((pState->bytesLeft == 0) && (pState->loopSamples != 0))
  1150. {
  1151. if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS)
  1152. return result;
  1153. pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop;
  1154. pState->flags &= ~PCM_FLAGS_EMPTY;
  1155. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "LinearPCMDecode: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ }
  1156. }
  1157. if (pState->bytesLeft)
  1158. {
  1159. /* check format byte for 8-bit samples */
  1160. if (pState->flags & PCM_FLAGS_8_BIT)
  1161. {
  1162. /* fetch left or mono sample */
  1163. if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
  1164. return result;
  1165. /* if unsigned */
  1166. if (pState->flags & PCM_FLAGS_UNSIGNED)
  1167. {
  1168. /*lint -e{734} converting unsigned 8-bit to signed 16-bit */
  1169. pState->decoderL.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000);
  1170. }
  1171. else
  1172. {
  1173. /*lint -e{734} converting signed 8-bit to signed 16-bit */
  1174. pState->decoderL.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8);
  1175. }
  1176. pState->bytesLeft--;
  1177. /* fetch right sample */
  1178. if(pState->flags & PCM_FLAGS_STEREO)
  1179. {
  1180. if ((result = EAS_HWGetByte(hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
  1181. return result;
  1182. /* if unsigned */
  1183. if (pState->flags & PCM_FLAGS_UNSIGNED)
  1184. {
  1185. /*lint -e{734} converting unsigned 8-bit to signed 16-bit */
  1186. pState->decoderR.x1 = (EAS_PCM)(((EAS_PCM) pState->srcByte << 8) ^ 0x8000);
  1187. }
  1188. else
  1189. {
  1190. /*lint -e{734} converting signed 8-bit to signed 16-bit */
  1191. pState->decoderR.x1 = (EAS_PCM)((EAS_PCM) pState->srcByte << 8);
  1192. }
  1193. pState->bytesLeft--;
  1194. }
  1195. }
  1196. /* must be 16-bit samples */
  1197. else
  1198. {
  1199. //unsigned 16 bit currently not supported
  1200. if (pState->flags & PCM_FLAGS_UNSIGNED)
  1201. {
  1202. return EAS_ERROR_INVALID_PCM_TYPE;
  1203. }
  1204. /* fetch left or mono sample */
  1205. if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderL.x1, EAS_FALSE)) != EAS_SUCCESS)
  1206. return result;
  1207. pState->bytesLeft -= 2;
  1208. /* fetch right sample */
  1209. if(pState->flags & PCM_FLAGS_STEREO)
  1210. {
  1211. if ((result = EAS_HWGetWord(hwInstData, pState->fileHandle, &pState->decoderR.x1, EAS_FALSE)) != EAS_SUCCESS)
  1212. return result;
  1213. pState->bytesLeft -= 2;
  1214. }
  1215. }
  1216. }
  1217. /* no more data, force zero samples */
  1218. else
  1219. pState->decoderL.x1 = pState->decoderR.x1 = 0;
  1220. return EAS_SUCCESS;
  1221. }
  1222. /*----------------------------------------------------------------------------
  1223. * LinearPCMLocate()
  1224. *----------------------------------------------------------------------------
  1225. * Purpose:
  1226. * Locate in a linear PCM stream
  1227. *----------------------------------------------------------------------------
  1228. */
  1229. static EAS_RESULT LinearPCMLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time)
  1230. {
  1231. EAS_RESULT result;
  1232. EAS_I32 temp;
  1233. EAS_I32 secs, msecs;
  1234. EAS_INT shift;
  1235. /* calculate size of sample frame */
  1236. if (pState->flags & PCM_FLAGS_8_BIT)
  1237. shift = 0;
  1238. else
  1239. shift = 1;
  1240. if (pState->flags & PCM_FLAGS_STEREO)
  1241. shift++;
  1242. /* break down into secs and msecs */
  1243. secs = time / 1000;
  1244. msecs = time - (secs * 1000);
  1245. /* calculate sample number fraction from msecs */
  1246. temp = (msecs * pState->sampleRate);
  1247. temp = (temp >> 10) + ((temp * 49) >> 21);
  1248. /* add integer sample count */
  1249. temp += secs * pState->sampleRate;
  1250. /* calculate the position based on sample frame size */
  1251. /*lint -e{703} use shift for performance */
  1252. temp <<= shift;
  1253. /* past end of sample? */
  1254. if (temp > (EAS_I32) pState->loopStart)
  1255. {
  1256. /* if not looped, flag error */
  1257. if (pState->loopSamples == 0)
  1258. {
  1259. pState->bytesLeft = 0;
  1260. pState->flags |= PCM_FLAGS_EMPTY;
  1261. return EAS_ERROR_LOCATE_BEYOND_END;
  1262. }
  1263. /* looped sample - calculate position in loop */
  1264. while (temp > (EAS_I32) pState->loopStart)
  1265. temp -= (EAS_I32) pState->loopStart;
  1266. }
  1267. /* seek to new position */
  1268. if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS)
  1269. return result;
  1270. /* reset state */
  1271. if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED))
  1272. pState->state = EAS_STATE_READY;
  1273. return EAS_SUCCESS;
  1274. }
  1275. /*----------------------------------------------------------------------------
  1276. * EAS_PESeek
  1277. *----------------------------------------------------------------------------
  1278. * Purpose:
  1279. * Locate to a particular byte in a PCM stream
  1280. *----------------------------------------------------------------------------
  1281. * This bit is tricky because the chunks may not be contiguous,
  1282. * so we have to rely on the parser to position in the file. We
  1283. * do this by seeking to the end of each chunk and simulating an
  1284. * empty buffer condition until we get to where we want to go.
  1285. *
  1286. * A better solution would be a parser API for re-positioning,
  1287. * but there isn't time at the moment to re-factor all the
  1288. * parsers to support a new API.
  1289. *----------------------------------------------------------------------------
  1290. */
  1291. EAS_RESULT EAS_PESeek (S_EAS_DATA *pEASData, S_PCM_STATE *pState, EAS_I32 *pLocation)
  1292. {
  1293. EAS_RESULT result;
  1294. /* seek to start of audio */
  1295. if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, pState->startPos)) != EAS_SUCCESS)
  1296. {
  1297. pState->state = EAS_STATE_ERROR;
  1298. return result;
  1299. }
  1300. pState->bytesLeft = pState->bytesLeftLoop;
  1301. /* skip through chunks until we find the right chunk */
  1302. while (*pLocation > (EAS_I32) pState->bytesLeft)
  1303. {
  1304. /* seek to end of audio chunk */
  1305. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", pState->bytesLeft); */ }
  1306. if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, pState->bytesLeft)) != EAS_SUCCESS)
  1307. {
  1308. pState->state = EAS_STATE_ERROR;
  1309. return result;
  1310. }
  1311. *pLocation -= pState->bytesLeft;
  1312. pState->bytesLeft = 0;
  1313. pState->flags |= PCM_FLAGS_EMPTY;
  1314. /* retrieve more data */
  1315. if (pState->pCallback)
  1316. (*pState->pCallback)(pEASData, pState->cbInstData, pState, EAS_STATE_EMPTY);
  1317. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: bytesLeft=%d, byte location = %d\n", pState->bytesLeft, *pLocation); */ }
  1318. /* no more samples */
  1319. if (pState->bytesLeft == 0)
  1320. return EAS_ERROR_LOCATE_BEYOND_END;
  1321. }
  1322. /* seek to new offset in current chunk */
  1323. if (*pLocation > 0)
  1324. {
  1325. { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "EAS_PESeek: Seek to offset = %d\n", *pLocation); */ }
  1326. if ((result = EAS_HWFileSeekOfs(pEASData->hwInstData, pState->fileHandle, *pLocation)) != EAS_SUCCESS)
  1327. {
  1328. pState->state = EAS_STATE_ERROR;
  1329. return result;
  1330. }
  1331. /* if not streamed, calculate number of bytes left */
  1332. if (pState->flags & PCM_FLAGS_STREAMING)
  1333. pState->bytesLeft = 0x7fffffff;
  1334. else
  1335. pState->bytesLeft -= *pLocation;
  1336. }
  1337. return EAS_SUCCESS;
  1338. }