• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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