summaryrefslogtreecommitdiff
path: root/noncore/multimedia/opierec/adpcm.c
Unidiff
Diffstat (limited to 'noncore/multimedia/opierec/adpcm.c') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/multimedia/opierec/adpcm.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/noncore/multimedia/opierec/adpcm.c b/noncore/multimedia/opierec/adpcm.c
new file mode 100644
index 0000000..716fefd
--- a/dev/null
+++ b/noncore/multimedia/opierec/adpcm.c
@@ -0,0 +1,252 @@
1/***********************************************************
2Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
3Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF 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 */
55static int indexTable[16] = {
56 -1, -1, -1, -1, 2, 4, 6, 8,
57 -1, -1, -1, -1, 2, 4, 6, 8,
58};
59
60static 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
72void
73adpcm_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=0; /* 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
175void
176adpcm_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=0; /* place to keep next 4-bit value */
191 int bufferstep=0; /* 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}