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 */
IMADecoderInit(EAS_DATA_HANDLE pEASData,S_PCM_STATE * pState)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 */
IMADecoderSample(EAS_DATA_HANDLE pEASData,S_PCM_STATE * pState)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 */
IMADecoderADPCM(S_DECODER_STATE * pState,EAS_U8 nibble)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 */
IMADecoderLocate(EAS_DATA_HANDLE pEASData,S_PCM_STATE * pState,EAS_I32 time)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