wonky sweep
[gbajam21] / tools / mmutil / adpcm.c
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
9  *                                                                          *
10  * Permission to use, copy, modify, and/or distribute this software for any *
11  * purpose with or without fee is hereby granted, provided that the above   *
12  * copyright notice and this permission notice appear in all copies.        *
13  *                                                                          *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
20  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
21  ****************************************************************************/
22
23 // thanks GBATEK for the ima-adpcm specification
24
25 #include <stdlib.h>
26 #include "defs.h"
27 #include "deftypes.h"
28 #include "mas.h"
29
30 const s8 IndexTable[8] = {
31     -1, -1, -1, -1, 2, 4, 6, 8
32 };
33
34 const u16 AdpcmTable[89] = {
35             7,     8,     9,    10,    11,    12,    13,    14,    16,    17,
36        19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
37        50,    55,    60,    66,    73,    80,    88,    97,   107,   118,
38       130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
39       337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
40       876,   963,  1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
41      2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
42      5894,  6484,  7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899,
43     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
44 };
45
46 static int read_sample( Sample* sample, int position )
47 {
48         int s;
49         if( sample->format & SAMPF_16BIT )
50         {
51                 s = ((s16*)sample->data)[position];
52         }
53         else
54         {
55                 // expand 8-bit value
56                 int a = ((s8*)sample->data)[position];
57                 s = (a<<8);
58         }
59         if( s < -32767 ) s = -32767;    // is this necessary?...
60         return s;
61 }
62
63 static int minmax( int value, int low, int high )
64 {
65         if( value < low ) value = low;
66         if( value > high ) value = high;
67         return value;
68 }
69
70 static int calc_delta( int diff, int step )
71 {
72         int delta = (step >> 3);        // t/8
73         
74         if( diff >= step ) {            // t/1
75                 diff -= step;
76                 delta += step;
77         }
78         if( diff >= (step>>1) ) {       // t/2
79                 diff -= step>>1;
80                 delta += step>>1;
81         }
82         if( diff >= (step>>2) ) {       // t/4
83                 diff -= step>>2;
84                 delta += step>>2;
85         }
86         return delta;
87 }
88
89 //----------------------------------------------------------------------
90 // Compresses a sample with IMA-ADPCM
91 // Make sure the data has proper alignment/length!
92 //----------------------------------------------------------------------
93 void adpcm_compress_sample( Sample* sample )
94 //----------------------------------------------------------------------
95 {
96         u32 x;
97         u8* output;
98
99         int prev_value;
100         int curr_value;
101         
102         int diff;
103         int data;
104         int delta;
105         
106         int index;
107         int step;
108         
109         // allocate space for sample (compressed size)
110         output = (u8*)malloc( sample->sample_length/2+4 );
111         
112         prev_value = read_sample( sample, 0 );
113         index = 0;
114
115         { // determine best (or close to best) initial table value
116
117                 int i;
118                 int smallest_error;
119                 int tmp_error;
120                 smallest_error = 9999999;
121
122
123                 diff = read_sample( sample, 1 ) - read_sample( sample, 0 );
124                 
125                 for( i = 0; i < 88; i++ )
126                 {
127                         tmp_error = calc_delta( diff, i ) - diff;
128                         if( tmp_error < smallest_error )
129                         {
130                                 smallest_error = tmp_error;
131                                 index = i;
132                         }
133                 }
134         }
135                 
136         // set data header
137         (*((u32*)output)) =             prev_value                      // initial PCM16 value
138                                                         | (index << 16);        // initial table index value
139         
140         step = AdpcmTable[index];
141         
142         for( x = 0; x < sample->sample_length; x++ )
143         {
144                 curr_value = read_sample( sample, x );
145                 
146                 diff = curr_value - prev_value;
147                 if( diff < 0 )
148                 {
149                         // negate difference & set negative bit
150                         diff = -diff;
151                         data = 8;
152                 }
153                 else
154                 {
155                         // clear negative flag
156                         data = 0;
157                 }
158                 
159                 /*
160                   difference calculation:
161                   Diff = AdpcmTable[Index]/8
162                   IF (data4bit AND 1) THEN Diff = Diff + AdpcmTable[Index]/4
163                   IF (data4bit AND 2) THEN Diff = Diff + AdpcmTable[Index]/2
164                   IF (data4bit AND 4) THEN Diff = Diff + AdpcmTable[Index]/1
165                 */      
166                 
167                 delta = (step >> 3);            // t/8 (always)
168                 
169                 if( diff >= step ) {            // t/1
170                         data |= 4;
171                         diff -= step;
172                         delta += step;
173                 }
174                 if( diff >= (step>>1) ) {       // t/2
175                         data |= 2;
176                         diff -= step>>1;
177                         delta += step>>1;
178                 }
179                 if( diff >= (step>>2) ) {       // t/4
180                         data |= 1;
181                         diff -= step>>2;
182                         delta += step>>2;
183                 }
184                 
185                 // add/subtract delta
186                 prev_value += (data&8) ? -delta : delta;
187                 
188                 // claamp output
189                 prev_value = minmax( prev_value, -0x7FFF, 0x7FFF );
190                                 
191                 // add index table value (and clamp)
192                 index = minmax( index + IndexTable[data & 7], 0, 88 );
193                 
194                 // read new step value
195                 step = AdpcmTable[index];
196                 
197                 // write output
198                 if( (x & 1) )
199                         output[(x>>1)+4] |= (data) << 4;
200                 else
201                         output[(x>>1)+4] = (data);
202         }
203
204         // delete old sample
205         free( sample->data );
206
207         // assign new sample
208         sample->data = output;
209
210         // new format
211         sample->format = SAMP_FORMAT_ADPCM;
212
213         // new length/loop
214         sample->sample_length = (sample->sample_length/2) +4;
215         sample->loop_start /= 2;
216         sample->loop_end /= 2;
217         
218         // step loop past adpcm header
219         sample->loop_start += 4;
220         sample->loop_end += 4;
221 }