1 /***********************************************************
2 Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
3 Netherlands.
4 
5                         All Rights Reserved
6 
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
14 
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 
23 ******************************************************************/
24 
25 /*
26 ** Intel/DVI ADPCM coder/decoder.
27 **
28 ** The algorithm for this coder was taken from the IMA Compatability Project
29 ** proceedings, Vol 2, Number 2; May 1992.
30 **
31 ** Version 1.2, 18-Dec-92.
32 **
33 ** Change log:
34 ** - Fixed a stupid bug, where the delta was computed as
35 **   stepsize*code/4 in stead of stepsize*(code+0.5)/4.
36 ** - There was an off-by-one error causing it to pick
37 **   an incorrect delta once in a blue moon.
38 ** - The NODIVMUL define has been removed. Computations are now always done
39 **   using shifts, adds and subtracts. It turned out that, because the standard
40 **   is defined using shift/add/subtract, you needed bits of fixup code
41 **   (because the div/mul simulation using shift/add/sub made some rounding
42 **   errors that real div/mul don't make) and all together the resultant code
43 **   ran slower than just using the shifts all the time.
44 ** - Changed some of the variable names to be more meaningful.
45 */
46 
47 #include "adpcm.h"
48 #include <stdio.h> /*DBG*/
49 
50 #ifndef __STDC__
51 #define signed
52 #endif
53 
54 /* Intel ADPCM step variation table */
55 static int indexTable[16] = {
56     -1, -1, -1, -1, 2, 4, 6, 8,
57     -1, -1, -1, -1, 2, 4, 6, 8,
58 };
59 
60 static int stepsizeTable[89] = {
61     7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
62     19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
63     50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
64     130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
65     337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
66     876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
67     2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
68     5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
69     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
70 };
71 
72 void
adpcm_coder(indata,outdata,len,state)73 adpcm_coder(indata, outdata, len, state)
74     short indata[];
75     char outdata[];
76     int len;
77     struct adpcm_state *state;
78 {
79     short *inp;			/* Input buffer pointer */
80     signed char *outp;		/* output buffer pointer */
81     int val;			/* Current input sample value */
82     int sign;			/* Current adpcm sign bit */
83     int delta;			/* Current adpcm output value */
84     int diff;			/* Difference between val and valprev */
85     int step;			/* Stepsize */
86     int valpred;		/* Predicted output value */
87     int vpdiff;			/* Current change to valpred */
88     int index;			/* Current step change index */
89     int outputbuffer;		/* place to keep previous 4-bit value */
90     int bufferstep;		/* toggle between outputbuffer/output */
91 
92     outp = (signed char *)outdata;
93     inp = indata;
94 
95     valpred = state->valprev;
96     index = state->index;
97     step = stepsizeTable[index];
98 
99     bufferstep = 1;
100 
101     for ( ; len > 0 ; len-- ) {
102 	val = *inp++;
103 
104 	/* Step 1 - compute difference with previous value */
105 	diff = val - valpred;
106 	sign = (diff < 0) ? 8 : 0;
107 	if ( sign ) diff = (-diff);
108 
109 	/* Step 2 - Divide and clamp */
110 	/* Note:
111 	** This code *approximately* computes:
112 	**    delta = diff*4/step;
113 	**    vpdiff = (delta+0.5)*step/4;
114 	** but in shift step bits are dropped. The net result of this is
115 	** that even if you have fast mul/div hardware you cannot put it to
116 	** good use since the fixup would be too expensive.
117 	*/
118 	delta = 0;
119 	vpdiff = (step >> 3);
120 
121 	if ( diff >= step ) {
122 	    delta = 4;
123 	    diff -= step;
124 	    vpdiff += step;
125 	}
126 	step >>= 1;
127 	if ( diff >= step  ) {
128 	    delta |= 2;
129 	    diff -= step;
130 	    vpdiff += step;
131 	}
132 	step >>= 1;
133 	if ( diff >= step ) {
134 	    delta |= 1;
135 	    vpdiff += step;
136 	}
137 
138 	/* Step 3 - Update previous value */
139 	if ( sign )
140 	  valpred -= vpdiff;
141 	else
142 	  valpred += vpdiff;
143 
144 	/* Step 4 - Clamp previous value to 16 bits */
145 	if ( valpred > 32767 )
146 	  valpred = 32767;
147 	else if ( valpred < -32768 )
148 	  valpred = -32768;
149 
150 	/* Step 5 - Assemble value, update index and step values */
151 	delta |= sign;
152 
153 	index += indexTable[delta];
154 	if ( index < 0 ) index = 0;
155 	if ( index > 88 ) index = 88;
156 	step = stepsizeTable[index];
157 
158 	/* Step 6 - Output value */
159 	if ( bufferstep ) {
160 	    outputbuffer = (delta << 4) & 0xf0;
161 	} else {
162 	    *outp++ = (delta & 0x0f) | outputbuffer;
163 	}
164 	bufferstep = !bufferstep;
165     }
166 
167     /* Output last step, if needed */
168     if ( !bufferstep )
169       *outp++ = outputbuffer;
170 
171     state->valprev = valpred;
172     state->index = index;
173 }
174 
175 void
adpcm_decoder(indata,outdata,len,state)176 adpcm_decoder(indata, outdata, len, state)
177     char indata[];
178     short outdata[];
179     int len;
180     struct adpcm_state *state;
181 {
182     signed char *inp;		/* Input buffer pointer */
183     short *outp;		/* output buffer pointer */
184     int sign;			/* Current adpcm sign bit */
185     int delta;			/* Current adpcm output value */
186     int step;			/* Stepsize */
187     int valpred;		/* Predicted value */
188     int vpdiff;			/* Current change to valpred */
189     int index;			/* Current step change index */
190     int inputbuffer;		/* place to keep next 4-bit value */
191     int bufferstep;		/* toggle between inputbuffer/input */
192 
193     outp = outdata;
194     inp = (signed char *)indata;
195 
196     valpred = state->valprev;
197     index = state->index;
198     step = stepsizeTable[index];
199 
200     bufferstep = 0;
201 
202     for ( ; len > 0 ; len-- ) {
203 
204 	/* Step 1 - get the delta value */
205 	if ( bufferstep ) {
206 	    delta = inputbuffer & 0xf;
207 	} else {
208 	    inputbuffer = *inp++;
209 	    delta = (inputbuffer >> 4) & 0xf;
210 	}
211 	bufferstep = !bufferstep;
212 
213 	/* Step 2 - Find new index value (for later) */
214 	index += indexTable[delta];
215 	if ( index < 0 ) index = 0;
216 	if ( index > 88 ) index = 88;
217 
218 	/* Step 3 - Separate sign and magnitude */
219 	sign = delta & 8;
220 	delta = delta & 7;
221 
222 	/* Step 4 - Compute difference and new predicted value */
223 	/*
224 	** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
225 	** in adpcm_coder.
226 	*/
227 	vpdiff = step >> 3;
228 	if ( delta & 4 ) vpdiff += step;
229 	if ( delta & 2 ) vpdiff += step>>1;
230 	if ( delta & 1 ) vpdiff += step>>2;
231 
232 	if ( sign )
233 	  valpred -= vpdiff;
234 	else
235 	  valpred += vpdiff;
236 
237 	/* Step 5 - clamp output value */
238 	if ( valpred > 32767 )
239 	  valpred = 32767;
240 	else if ( valpred < -32768 )
241 	  valpred = -32768;
242 
243 	/* Step 6 - Update step value */
244 	step = stepsizeTable[index];
245 
246 	/* Step 7 - Output value */
247 	*outp++ = valpred;
248     }
249 
250     state->valprev = valpred;
251     state->index = index;
252 }
253