Home | History | Annotate | Download | only in lib_src
      1 /*----------------------------------------------------------------------------
      2  *
      3  * File:
      4  * eas_imaadpcm.c
      5  *
      6  * Contents and purpose:
      7  * Implements the IMA ADPCM decoder
      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: 847 $
     26  *   $Date: 2007-08-27 21:30:08 -0700 (Mon, 27 Aug 2007) $
     27  *----------------------------------------------------------------------------
     28 */
     29 
     30 #include "eas_data.h"
     31 #include "eas_host.h"
     32 #include "eas_pcm.h"
     33 #include "eas_math.h"
     34 #include "eas_report.h"
     35 
     36 // #define _DEBUG_IMA_ADPCM_LOCATE
     37 
     38 /*----------------------------------------------------------------------------
     39  * externs
     40  *----------------------------------------------------------------------------
     41 */
     42 extern const EAS_I16 imaIndexTable[];
     43 extern const EAS_I16 imaStepSizeTable[];
     44 
     45 /*----------------------------------------------------------------------------
     46  * prototypes
     47  *----------------------------------------------------------------------------
     48 */
     49 static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
     50 static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState);
     51 static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble);
     52 static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time);
     53 
     54 /*----------------------------------------------------------------------------
     55  * IMA ADPCM Decoder interface
     56  *----------------------------------------------------------------------------
     57 */
     58 const S_DECODER_INTERFACE IMADecoder =
     59 {
     60     IMADecoderInit,
     61     IMADecoderSample,
     62     IMADecoderLocate
     63 };
     64 
     65 /*----------------------------------------------------------------------------
     66  * IMADecoderInit()
     67  *----------------------------------------------------------------------------
     68  * Purpose:
     69  * Initializes the IMA ADPCM decoder
     70  *
     71  * Inputs:
     72  *
     73  *
     74  * Outputs:
     75  *
     76  *
     77  * Side Effects:
     78  *
     79  *----------------------------------------------------------------------------
     80 */
     81 /*lint -esym(715, pEASData) common decoder interface - pEASData not used */
     82 static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
     83 {
     84     pState->decoderL.step = 0;
     85     pState->decoderR.step = 0;
     86     return EAS_SUCCESS;
     87 }
     88 
     89 /*----------------------------------------------------------------------------
     90  * IMADecoderSample()
     91  *----------------------------------------------------------------------------
     92  * Purpose:
     93  * Decodes an IMA ADPCM sample
     94  *
     95  * Inputs:
     96  *
     97  *
     98  * Outputs:
     99  *
    100  *
    101  * Side Effects:
    102  *
    103  *----------------------------------------------------------------------------
    104 */
    105 static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState)
    106 {
    107     EAS_RESULT result;
    108     EAS_I16 sTemp;
    109 
    110     /* if high nibble, decode */
    111     if (pState->hiNibble)
    112     {
    113         IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte >> 4));
    114         pState->hiNibble = EAS_FALSE;
    115     }
    116 
    117     /* low nibble, need to fetch another byte */
    118     else
    119     {
    120         /* check for loop */
    121         if ((pState->bytesLeft == 0) && (pState->loopSamples != 0))
    122         {
    123             /* seek to start of loop */
    124             if ((result = EAS_HWFileSeek(pEASData->hwInstData, pState->fileHandle, (EAS_I32) (pState->startPos + pState->loopLocation))) != EAS_SUCCESS)
    125                 return result;
    126             pState->bytesLeft = pState->byteCount = (EAS_I32) pState->bytesLeftLoop;
    127             pState->blockCount = 0;
    128             pState->flags &= ~PCM_FLAGS_EMPTY;
    129             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMADecoderSample: Rewind file to %d, bytesLeft = %d\n", pState->startPos, pState->bytesLeft); */ }
    130         }
    131 
    132         /* if start of block, fetch new predictor and step index */
    133         if ((pState->blockSize != 0) && (pState->blockCount == 0) && (pState->bytesLeft != 0))
    134         {
    135 
    136             /* get predicted sample for left channel */
    137             if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
    138                 return result;
    139 #ifdef _DEBUG_IMA_ADPCM
    140             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Predictor: Was %d, now %d\n", pState->decoderL.acc, sTemp); */ }
    141 #endif
    142             pState->decoderL.acc = pState->decoderL.x1 = sTemp;
    143 
    144             /* get step index for left channel - upper 8 bits are reserved */
    145             if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
    146                 return result;
    147 #ifdef _DEBUG_IMA_ADPCM
    148             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderL.step, sTemp); */ }
    149 #endif
    150             pState->decoderL.step = sTemp & 0xff;
    151 
    152             if (pState->flags & PCM_FLAGS_STEREO)
    153             {
    154                 /* get predicted sample for right channel */
    155                 if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
    156                     return result;
    157                 pState->decoderR.acc = pState->decoderR.x1 = sTemp;
    158 
    159                 /* get step index for right channel - upper 8 bits are reserved */
    160                 if ((result = EAS_HWGetWord(pEASData->hwInstData, pState->fileHandle, &sTemp, EAS_FALSE)) != EAS_SUCCESS)
    161                     return result;
    162 #ifdef _DEBUG_IMA_ADPCM
    163                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Step: Was %d, now %d\n", pState->decoderR.step, sTemp); */ }
    164 #endif
    165                 pState->decoderR.step = sTemp & 0xff;
    166 
    167                 pState->blockCount = pState->blockSize - 8;
    168                 pState->bytesLeft -= 8;
    169             }
    170             else
    171             {
    172                 pState->blockCount = pState->blockSize - 4;
    173                 pState->bytesLeft -= 4;
    174             }
    175         }
    176         else
    177         {
    178 
    179             /* get another ADPCM data pair */
    180             if (pState->bytesLeft)
    181             {
    182 
    183                 if ((result = EAS_HWGetByte(pEASData->hwInstData, pState->fileHandle, &pState->srcByte)) != EAS_SUCCESS)
    184                     return result;
    185 
    186                 /* decode the low nibble */
    187                 pState->bytesLeft--;
    188                 pState->blockCount--;
    189                 IMADecoderADPCM(&pState->decoderL, (EAS_U8)(pState->srcByte & 0x0f));
    190 
    191                 if (pState->flags & PCM_FLAGS_STEREO)
    192                     IMADecoderADPCM(&pState->decoderR, (EAS_U8)(pState->srcByte >> 4));
    193                 else
    194                     pState->hiNibble = EAS_TRUE;
    195             }
    196 
    197             /* out of ADPCM data, generate enough samples to fill buffer */
    198             else
    199             {
    200                 pState->decoderL.x1 = pState->decoderL.x0;
    201                 pState->decoderR.x1 = pState->decoderR.x0;
    202             }
    203         }
    204     }
    205 
    206     return EAS_SUCCESS;
    207 }
    208 
    209 /*----------------------------------------------------------------------------
    210  * IMADecoderADPCM()
    211  *----------------------------------------------------------------------------
    212  * Purpose:
    213  * Decodes an IMA ADPCM sample
    214  *
    215  * Inputs:
    216  *
    217  *
    218  * Outputs:
    219  *
    220  *
    221  * Side Effects:
    222  *
    223  *----------------------------------------------------------------------------
    224 */
    225 static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble)
    226 {
    227     EAS_INT delta;
    228     EAS_INT stepSize;
    229 
    230     /* get stepsize from table */
    231     stepSize = imaStepSizeTable[pState->step];
    232 
    233     /* delta = (abs(delta) + 0.5) * step / 4 */
    234     delta = 0;
    235     if (nibble & 4)
    236         delta += stepSize;
    237 
    238     if (nibble & 2)
    239         /*lint -e{702} use shift for performance */
    240         delta += stepSize >> 1;
    241 
    242     if (nibble & 1)
    243         /*lint -e{702} use shift for performance */
    244         delta += stepSize >> 2;
    245 
    246     /*lint -e{702} use shift for performance */
    247     delta += stepSize >> 3;
    248 
    249     /* integrate the delta */
    250     if (nibble & 8)
    251       pState->acc -= delta;
    252     else
    253       pState->acc += delta;
    254 
    255     /* saturate */
    256     if (pState->acc > 32767)
    257         pState->acc = 32767;
    258     if (pState->acc < -32768)
    259         pState->acc = -32768;
    260     pState->x1 = (EAS_PCM) pState->acc;
    261 
    262     /* compute new step size */
    263     pState->step += imaIndexTable[nibble];
    264     if (pState->step < 0)
    265         pState->step = 0;
    266     if (pState->step > 88)
    267         pState->step = 88;
    268 
    269 #ifdef _DEBUG_IMA_ADPCM
    270     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "In=%u, Pred=%d, Step=%d\n", nibble, pState->acc,  imaStepSizeTable[pState->step]); */ }
    271 #endif
    272 }
    273 
    274 /*----------------------------------------------------------------------------
    275  * IMADecoderLocate()
    276  *----------------------------------------------------------------------------
    277  * Locate in an IMA ADPCM stream
    278  *----------------------------------------------------------------------------
    279 */
    280 static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time)
    281 {
    282     EAS_RESULT result;
    283     EAS_I32 temp;
    284     EAS_I32 samplesPerBlock;
    285     EAS_I32 secs, msecs;
    286 
    287     /* no need to calculate if time is zero */
    288     if (time == 0)
    289         temp = 0;
    290 
    291     /* not zero */
    292     else
    293     {
    294 
    295         /* can't seek if not a blocked file */
    296         if (pState->blockSize == 0)
    297             return EAS_ERROR_FEATURE_NOT_AVAILABLE;
    298 
    299         /* calculate number of samples per block */
    300         if (pState->flags & PCM_FLAGS_STEREO)
    301             samplesPerBlock = pState->blockSize - 7;
    302         else
    303             samplesPerBlock = (pState->blockSize << 1) - 7;
    304 
    305         /* break down into secs and msecs */
    306         secs = time / 1000;
    307         msecs = time - (secs * 1000);
    308 
    309         /* calculate sample number fraction from msecs */
    310         temp = (msecs * pState->sampleRate);
    311         temp = (temp >> 10) + ((temp * 49) >> 21);
    312 
    313         /* add integer sample count */
    314         temp += secs * pState->sampleRate;
    315 
    316 #ifdef _DEBUG_IMA_ADPCM_LOCATE
    317         EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000006 , time, temp);
    318 #endif
    319 
    320         /* for looped samples, calculate position in the loop */
    321         if ((temp > pState->byteCount) && (pState->loopSamples != 0))
    322         {
    323             EAS_I32 numBlocks;
    324             EAS_I32 samplesPerLoop;
    325             EAS_I32 samplesInLastBlock;
    326 
    327             numBlocks = (EAS_I32) (pState->loopStart / pState->blockSize);
    328             samplesInLastBlock = (EAS_I32) pState->loopStart - (numBlocks * pState->blockSize);
    329             if (samplesInLastBlock)
    330             {
    331                 if (pState->flags & PCM_FLAGS_STEREO)
    332                     samplesInLastBlock = samplesInLastBlock - 7;
    333                 else
    334                     /*lint -e{703} use shift for performance */
    335                     samplesInLastBlock = (samplesInLastBlock << 1) - 7;
    336             }
    337             samplesPerLoop = numBlocks * samplesPerBlock + samplesInLastBlock;
    338             temp = temp % samplesPerLoop;
    339 #ifdef _DEBUG_IMA_ADPCM_LOCATE
    340             EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000007 , numBlocks, samplesPerLoop, samplesInLastBlock, temp);
    341 #endif
    342         }
    343 
    344         /* find start of block for requested sample */
    345         temp = (temp / samplesPerBlock) * pState->blockSize;
    346 #ifdef _DEBUG_IMA_ADPCM_LOCATE
    347         EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000008 , temp);
    348 #endif
    349 
    350     }
    351 
    352     /* seek to new location */
    353     if ((result = EAS_PESeek(pEASData, pState, &temp)) != EAS_SUCCESS)
    354         return result;
    355 
    356 #ifdef _DEBUG_IMA_ADPCM_LOCATE
    357     EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0x2380b977, 0x00000009 , pState->bytesLeft);
    358 #endif
    359 
    360     /* reset state */
    361     pState->blockCount = 0;
    362     pState->hiNibble = EAS_FALSE;
    363     if ((pState->state != EAS_STATE_PAUSING) && (pState->state != EAS_STATE_PAUSED))
    364         pState->state = EAS_STATE_READY;
    365 
    366     return EAS_SUCCESS;
    367 }
    368 
    369