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*/ 42extern const EAS_I16 imaIndexTable[]; 43extern const EAS_I16 imaStepSizeTable[]; 44 45/*---------------------------------------------------------------------------- 46 * prototypes 47 *---------------------------------------------------------------------------- 48*/ 49static EAS_RESULT IMADecoderInit (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); 50static EAS_RESULT IMADecoderSample (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState); 51static void IMADecoderADPCM (S_DECODER_STATE *pState, EAS_U8 nibble); 52static EAS_RESULT IMADecoderLocate (EAS_DATA_HANDLE pEASData, S_PCM_STATE *pState, EAS_I32 time); 53 54/*---------------------------------------------------------------------------- 55 * IMA ADPCM Decoder interface 56 *---------------------------------------------------------------------------- 57*/ 58const 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 */ 82static 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*/ 105static 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*/ 225static 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*/ 280static 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