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