1 /* libSoX ima_rw.c -- codex utilities for WAV_FORMAT_IMA_ADPCM
2  * Copyright (C) 1999 Stanley J. Brooks <stabro@megsinet.net>
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; either version 2.1 of the License, or (at
7  * your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 
18 */
19 
20 #include "sox_i.h"
21 #include "ima_rw.h"
22 
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 /*
27  *
28  * Lookup tables for IMA ADPCM format
29  *
30  */
31 #define ISSTMAX 88
32 
33 static const int imaStepSizeTable[ISSTMAX + 1] = {
34         7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34,
35         37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
36         157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
37         544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
38         1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
39         4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
40         11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
41         27086, 29794, 32767
42 };
43 
44 #define imaStateAdjust(c) (((c)<4)? -1:(2*(c)-6))
45 /* +0 - +3, decrease step size */
46 /* +4 - +7, increase step size */
47 /* -0 - -3, decrease step size */
48 /* -4 - -7, increase step size */
49 
50 static unsigned char imaStateAdjustTable[ISSTMAX+1][8];
51 
lsx_ima_init_table(void)52 void lsx_ima_init_table(void)
53 {
54         int i,j,k;
55         for (i=0; i<=ISSTMAX; i++) {
56                 for (j=0; j<8; j++) {
57                         k = i + imaStateAdjust(j);
58                         if (k<0) k=0;
59                         else if (k>ISSTMAX) k=ISSTMAX;
60                         imaStateAdjustTable[i][j] = k;
61                 }
62         }
63 }
64 
ImaExpandS(unsigned ch,unsigned chans,const unsigned char * ibuff,SAMPL * obuff,int n,unsigned o_inc)65 static void ImaExpandS(
66         unsigned ch,             /* channel number to decode, REQUIRE 0 <= ch < chans  */
67         unsigned chans,          /* total channels             */
68         const unsigned char *ibuff,/* input buffer[blockAlign]   */
69         SAMPL *obuff,       /* obuff[n] will be output samples */
70         int n,              /* samples to decode PER channel, REQUIRE n % 8 == 1  */
71         unsigned o_inc           /* index difference between successive output samples */
72 )
73 {
74         const unsigned char *ip;
75         int i_inc;
76         SAMPL *op;
77         int i, val, state;
78 
79         ip = ibuff + 4*ch;     /* input pointer to 4-byte block state-initializer   */
80         i_inc = 4*(chans-1);   /* amount by which to incr ip after each 4-byte read */
81         val = (short)(ip[0] + (ip[1]<<8)); /* need cast for sign-extend */
82         state = ip[2];
83         if (state > ISSTMAX) {
84                 lsx_warn("IMA_ADPCM block ch%d initial-state (%d) out of range", ch, state);
85                 state = 0;
86         }
87         /* specs say to ignore ip[3] , but write it as 0 */
88         ip += 4+i_inc;
89 
90         op = obuff;
91         *op = val;      /* 1st output sample for this channel */
92         op += o_inc;
93 
94         for (i = 1; i < n; i++) {
95                 int step,dp,c,cm;
96 
97                 if (i&1) {         /* 1st of pair */
98                         cm = *ip & 0x0f;
99                 } else {
100                         cm = (*ip++)>>4;
101                         if ((i&7) == 0)  /* ends the 8-sample input block for this channel */
102                                 ip += i_inc;   /* skip ip for next group */
103                 }
104 
105                 step = imaStepSizeTable[state];
106                 /* Update the state for the next sample */
107                 c = cm & 0x07;
108                 state = imaStateAdjustTable[state][c];
109 
110                 dp = 0;
111                 if (c & 4) dp += step;
112                 step = step >> 1;
113                 if (c & 2) dp += step;
114                 step = step >> 1;
115                 if (c & 1) dp += step;
116                 step = step >> 1;
117                 dp += step;
118 
119                 if (c != cm) {
120                         val -= dp;
121                         if (val<-0x8000) val = -0x8000;
122                 } else {
123                         val += dp;
124                         if (val>0x7fff) val = 0x7fff;
125                 }
126                 *op = val;
127                 op += o_inc;
128         }
129         return;
130 }
131 
132 /* lsx_ima_block_expand_i() outputs interleaved samples into one output buffer */
lsx_ima_block_expand_i(unsigned chans,const unsigned char * ibuff,SAMPL * obuff,int n)133 void lsx_ima_block_expand_i(
134         unsigned chans,          /* total channels             */
135         const unsigned char *ibuff,/* input buffer[blockAlign]   */
136         SAMPL *obuff,       /* output samples, n*chans    */
137         int n               /* samples to decode PER channel, REQUIRE n % 8 == 1  */
138 )
139 {
140         unsigned ch;
141         for (ch=0; ch<chans; ch++)
142                 ImaExpandS(ch, chans, ibuff, obuff+ch, n, chans);
143 }
144 
145 /* lsx_ima_block_expand_m() outputs non-interleaved samples into chan separate output buffers */
lsx_ima_block_expand_m(unsigned chans,const unsigned char * ibuff,SAMPL ** obuffs,int n)146 void lsx_ima_block_expand_m(
147         unsigned chans,          /* total channels             */
148         const unsigned char *ibuff,/* input buffer[blockAlign]   */
149         SAMPL **obuffs,     /* chan output sample buffers, each takes n samples */
150         int n               /* samples to decode PER channel, REQUIRE n % 8 == 1  */
151 )
152 {
153         unsigned ch;
154         for (ch=0; ch<chans; ch++)
155                 ImaExpandS(ch, chans, ibuff, obuffs[ch], n, 1);
156 }
157 
ImaMashS(unsigned ch,unsigned chans,int v0,const SAMPL * ibuff,int n,int * st,unsigned char * obuff)158 static int ImaMashS(
159         unsigned ch,             /* channel number to encode, REQUIRE 0 <= ch < chans  */
160         unsigned chans,          /* total channels */
161         int v0,           /* value to use as starting prediction0 */
162         const SAMPL *ibuff, /* ibuff[] is interleaved input samples */
163         int n,              /* samples to encode PER channel, REQUIRE n % 8 == 1 */
164         int *st,            /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
165         unsigned char *obuff /* output buffer[blockAlign], or NULL for no output  */
166 )
167 {
168         const SAMPL *ip, *itop;
169         unsigned char *op;
170         int o_inc = 0;      /* set 0 only to shut up gcc's 'might be uninitialized' */
171         int i, val;
172         int state;
173         double d2;  /* long long is okay also, speed abt the same */
174 
175         ip = ibuff + ch;       /* point ip to 1st input sample for this channel */
176         itop = ibuff + n*chans;
177         val = *ip - v0; ip += chans;/* 1st input sample for this channel */
178         d2 = val*val;/* d2 will be sum of squares of errors, given input v0 and *st */
179         val = v0;
180 
181         op = obuff;            /* output pointer (or NULL) */
182         if (op) {              /* NULL means don't output, just compute the rms error */
183                 op += 4*ch;          /* where to put this channel's 4-byte block state-initializer */
184                 o_inc = 4*(chans-1); /* amount by which to incr op after each 4-byte written */
185                 *op++ = val; *op++ = val>>8;
186                 *op++ = *st; *op++ = 0; /* they could have put a mid-block state-correction here  */
187                 op += o_inc;            /* _sigh_   NEVER waste a byte.      It's a rule!         */
188         }
189 
190         state = *st;
191 
192         for (i = 0; ip < itop; ip+=chans) {
193                 int step,d,dp,c;
194 
195                 d = *ip - val;  /* difference between last prediction and current sample */
196 
197                 step = imaStepSizeTable[state];
198                 c = (abs(d)<<2)/step;
199                 if (c > 7) c = 7;
200                 /* Update the state for the next sample */
201                 state = imaStateAdjustTable[state][c];
202 
203                 if (op) {   /* if we want output, put it in proper place */
204                         int cm = c;
205                         if (d<0) cm |= 8;
206                         if (i&1) {       /* odd numbered output */
207                                 *op++ |= (cm<<4);
208                                 if (i == 7)    /* ends the 8-sample output block for this channel */
209                                         op += o_inc; /* skip op for next group */
210                         } else {
211                                 *op = cm;
212                         }
213                         i = (i+1) & 0x07;
214                 }
215 
216                 dp = 0;
217                 if (c & 4) dp += step;
218                 step = step >> 1;
219                 if (c & 2) dp += step;
220                 step = step >> 1;
221                 if (c & 1) dp += step;
222                 step = step >> 1;
223                 dp += step;
224 
225                 if (d<0) {
226                         val -= dp;
227                         if (val<-0x8000) val = -0x8000;
228                 } else {
229                         val += dp;
230                         if (val>0x7fff) val = 0x7fff;
231                 }
232 
233                 {
234                         int x = *ip - val;
235                         d2 += x*x;
236                 }
237 
238         }
239         d2 /= n; /* be sure it's non-negative */
240         *st = state;
241         return (int) sqrt(d2);
242 }
243 
244 /* mash one channel... if you want to use opt>0, 9 is a reasonable value */
ImaMashChannel(unsigned ch,unsigned chans,const SAMPL * ip,int n,int * st,unsigned char * obuff,int opt)245 inline static void ImaMashChannel(
246         unsigned ch,             /* channel number to encode, REQUIRE 0 <= ch < chans  */
247         unsigned chans,          /* total channels */
248         const SAMPL *ip,    /* ip[] is interleaved input samples */
249         int n,              /* samples to encode PER channel, REQUIRE n % 8 == 1 */
250         int *st,            /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
251         unsigned char *obuff, /* output buffer[blockAlign] */
252         int opt             /* non-zero allows some cpu-intensive code to improve output */
253 )
254 {
255         int snext;
256         int s0,d0;
257 
258         s0 = *st;
259         if (opt>0) {
260                 int low,hi,w;
261                 int low0,hi0;
262                 snext = s0;
263                 d0 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
264 
265                 w = 0;
266                 low=hi=s0;
267                 low0 = low-opt; if (low0<0) low0=0;
268                 hi0 = hi+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
269                 while (low>low0 || hi<hi0) {
270                         if (!w && low>low0) {
271                                 int d2;
272                                 snext = --low;
273                                 d2 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
274                                 if (d2<d0) {
275                                         d0=d2; s0=low;
276                                         low0 = low-opt; if (low0<0) low0=0;
277                                         hi0 = low+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
278                                 }
279                         }
280                         if (w && hi<hi0) {
281                                 int d2;
282                                 snext = ++hi;
283                                 d2 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
284                                 if (d2<d0) {
285                                         d0=d2; s0=hi;
286                                         low0 = hi-opt; if (low0<0) low0=0;
287                                         hi0 = hi+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
288                                 }
289                         }
290                         w=1-w;
291                 }
292                 *st = s0;
293         }
294         ImaMashS(ch, chans, ip[ch], ip,n,st, obuff);
295 }
296 
297 /* mash one block.  if you want to use opt>0, 9 is a reasonable value */
lsx_ima_block_mash_i(unsigned chans,const SAMPL * ip,int n,int * st,unsigned char * obuff,int opt)298 void lsx_ima_block_mash_i(
299         unsigned chans,          /* total channels */
300         const SAMPL *ip,    /* ip[] is interleaved input samples */
301         int n,              /* samples to encode PER channel, REQUIRE n % 8 == 1 */
302         int *st,            /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
303         unsigned char *obuff, /* output buffer[blockAlign] */
304         int opt             /* non-zero allows some cpu-intensive code to improve output */
305 )
306 {
307         unsigned ch;
308         for (ch=0; ch<chans; ch++)
309                 ImaMashChannel(ch, chans, ip, n, st+ch, obuff, opt);
310 }
311 
312 /*
313  * lsx_ima_samples_in(dataLen, chans, blockAlign, samplesPerBlock)
314  *  returns the number of samples/channel which would go
315  *  in the dataLen, given the other parameters ...
316  *  if input samplesPerBlock is 0, then returns the max
317  *  samplesPerBlock which would go into a block of size blockAlign
318  *  Yes, it is confusing.
319  */
lsx_ima_samples_in(size_t dataLen,size_t chans,size_t blockAlign,size_t samplesPerBlock)320 size_t lsx_ima_samples_in(
321   size_t dataLen,
322   size_t chans,
323   size_t blockAlign,
324   size_t samplesPerBlock
325 )
326 {
327   size_t m, n;
328 
329   if (samplesPerBlock) {
330     n = (dataLen / blockAlign) * samplesPerBlock;
331     m = (dataLen % blockAlign);
332   } else {
333     n = 0;
334     m = blockAlign;
335   }
336   if (m >= (size_t)4*chans) {
337     m -= 4*chans;    /* number of bytes beyond block-header */
338     m /= 4*chans;    /* number of 4-byte blocks/channel beyond header */
339     m = 8*m + 1;     /* samples/chan beyond header + 1 in header */
340     if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock;
341     n += m;
342   }
343   return n;
344   /*wSamplesPerBlock = ((wBlockAlign - 4*wChannels)/(4*wChannels))*8 + 1;*/
345 }
346 
347 /*
348  * size_t lsx_ima_bytes_per_block(chans, samplesPerBlock)
349  *   return minimum blocksize which would be required
350  *   to encode number of chans with given samplesPerBlock
351  */
lsx_ima_bytes_per_block(size_t chans,size_t samplesPerBlock)352 size_t lsx_ima_bytes_per_block(
353   size_t chans,
354   size_t samplesPerBlock
355 )
356 {
357   size_t n;
358   /* per channel, ima has blocks of len 4, the 1st has 1st sample, the others
359    * up to 8 samples per block,
360    * so number of later blocks is (nsamp-1 + 7)/8, total blocks/chan is
361    * (nsamp-1+7)/8 + 1 = (nsamp+14)/8
362    */
363   n = ((size_t)samplesPerBlock + 14)/8 * 4 * chans;
364   return n;
365 }
366