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