PS2SDK
PS2 Homebrew Libraries
adpcm.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2005, James Lee (jbit<at>jbit<dot>net)
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 
12 
13 /*
14  Based on:
15  PSX VAG-Packer, hacked by bITmASTER@bigfoot.com, hacked by jbit :)
16  jbit's note:
17 */
18 
19 #include <math.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include "adpcm.h"
24 
25 #define ADPCM_LOOP_START 4 /* Set on first block of looped data */
26 #define ADPCM_LOOP 2 /* Set on all blocks (?that are inside the loop?) */
27 #define ADPCM_LOOP_END 1 /* Set on last block to loop */
28 
29 #define PACKED __attribute__((packed))
30 
31 typedef struct
32 {
33  unsigned shift: 4 PACKED;
34  unsigned predict: 4 PACKED;
35  uint8_t flags;
36  uint8_t sample[14]; /* 4bits each */
37 } AdpcmBlock;
38 
39 static void find_predict(AdpcmSetup *set, AdpcmBlock *adpcm, double *samples);
40 static void pack(AdpcmSetup *set, AdpcmBlock *adpcm, const double *samples);
41 
42 
43 AdpcmSetup *AdpcmCreate(AdpcmGetPCMfunc get, void *getpriv, AdpcmPutADPCMfunc put, void *putpriv, int loopstart)
44 {
45  AdpcmSetup *set;
46 
47  set = malloc(sizeof(AdpcmSetup));
48  if (set==NULL)
49  return(NULL);
50 
51  set->s_1 = set->s_2 = 0.0;
52  set->ps_1 = set->ps_2 = 0.0;
53 
54  set->curblock = 0;
55 
56  if (loopstart<0) /* disable looping (single shot) */
57  set->loopstart = -1;
58  else
59  set->loopstart = loopstart;
60 
61  set->GetPCM = get;
62  set->getpriv = getpriv;
63 
64  set->PutADPCM = put;
65  set->putpriv = putpriv;
66  set->pad = 0;
67  return(set);
68 }
69 
70 int AdpcmDestroy(AdpcmSetup *set)
71 {
72  free(set);
73  return(0);
74 }
75 
76 int AdpcmEncode(AdpcmSetup *set, int blocks)
77 {
78  AdpcmBlock adpcm;
79  double samples[28];
80  int procblocks;
81 
82  for (procblocks=0;procblocks<blocks;procblocks++)
83  {
84  int ret;
85  adpcm.flags = 0;
86 
87  for (int j=0;j<28;j++)
88  samples[j] = 0.0;
89 
90  ret = set->GetPCM(set->getpriv, samples, 28);
91  if (ret<0)
92  return(-1);
93  if (ret<28)
94  {
95  printf("loop end!\n");
96  adpcm.flags = ADPCM_LOOP_END;
97  }
98 
99  if (set->loopstart>=0)
100  {
101  adpcm.flags |= ADPCM_LOOP;
102  if (set->curblock == set->loopstart)
103  {
104  printf("loop start!\n");
105  adpcm.flags |= ADPCM_LOOP_START;
106  }
107  }
108 
109 
110  find_predict(set, &adpcm, samples);
111  pack(set, &adpcm, samples);
112 
113  if (set->PutADPCM(set->putpriv, &adpcm, 16)<0)
114  return(-1);
115 
116  set->curblock++;
117  if (ret<28)
118  break;
119  }
120 
121  if (set->loopstart<0 && procblocks<blocks)
122  {
123  /* this block essentialy loops to itself and contains no data */
124  adpcm.predict = 0;
125  adpcm.shift = 0;
126  adpcm.flags = ADPCM_LOOP_START | ADPCM_LOOP | ADPCM_LOOP_END;
127 
128  for (int i=0;i<14;i++)
129  adpcm.sample[i] = 0;
130  if (set->PutADPCM(set->putpriv, &adpcm, 16)<0)
131  return(-1);
132  set->curblock++;
133  }
134 
135  if (procblocks<blocks && set->pad)
136  {
137  int padblocks = blocks-(set->curblock%blocks);
138 
139  adpcm.predict = 0;
140  adpcm.shift = 0;
141  adpcm.flags = ADPCM_LOOP_START | ADPCM_LOOP | ADPCM_LOOP_END;
142  for (int i=0;i<14;i++)
143  adpcm.sample[i] = 0;
144 
145 
146  for (int i=0;i<padblocks;i++)
147  {
148  if (set->PutADPCM(set->putpriv, &adpcm, 16)<0)
149  return(-1);
150  set->curblock++;
151  }
152  }
153 
154  return(procblocks);
155 }
156 
157 static double f[5][2] =
158 {
159  { 0.0, 0.0},
160  { -60.0 / 64.0, 0.0},
161  { -115.0 / 64.0, 52.0 / 64.0},
162  { -98.0 / 64.0, 55.0 / 64.0},
163  { -122.0 / 64.0, 60.0 / 64.0}
164 };
165 #define MAX(_a,_b) ((_a)>(_b) ? (_a):(_b))
166 #define MIN(_a,_b) ((_a)<(_b) ? (_a):(_b))
167 #define CLAMP(_v,_min,_max) MIN(MAX(_v,_min),_max);
168 
169 static void find_predict(AdpcmSetup *set, AdpcmBlock *adpcm, double *samples)
170 {
171  double buffer[28][5];
172  double min = 1e10;
173  double max[5];
174  double ds;
175  int min2;
176  int shift_mask;
177  double s_0, s_1, s_2;
178 
179  for (int i=0;i<5;i++)
180  {
181  max[i] = 0.0;
182  s_1 = set->s_1;
183  s_2 = set->s_2;
184 
185  for (int j=0;j<28;j++)
186  {
187  s_0 = CLAMP(samples[j],-30720.0,30719.0);
188 
189  ds = s_0 + s_1 * f[i][0] + s_2 * f[i][1];
190  buffer[j][i] = ds;
191  if (fabs(ds) > max[i])
192  max[i] = fabs(ds);
193 
194  s_2 = s_1;
195  s_1 = s_0;
196  }
197 
198  if ( max[i] < min )
199  {
200  min = max[i];
201  adpcm->predict = i;
202  }
203  if (min <= 7)
204  {
205  adpcm->predict = 0;
206  break;
207  }
208  }
209 
210  set->s_1 = s_1;
211  set->s_2 = s_2;
212 
213  for (int i=0;i<28;i++ )
214  samples[i] = buffer[i][adpcm->predict];
215 
216  min2 = (int)min;
217  shift_mask = 0x4000;
218  adpcm->shift = 0;
219 
220  while(adpcm->shift < 12)
221  {
222  if (shift_mask & ( min2 + (shift_mask>>3) ))
223  break;
224  adpcm->shift++;
225  shift_mask = shift_mask >> 1;
226  }
227 }
228 
229 static void pack(AdpcmSetup *set, AdpcmBlock *adpcm, const double *samples)
230 {
231  double s_1, s_2;
232  short four_bit[28];
233 
234  s_1 = set->ps_1;
235  s_2 = set->ps_2;
236 
237  for (int i=0;i<28;i++)
238  {
239  double ds;
240  int di;
241  double s_0;
242 
243  s_0 = samples[i] + s_1 * f[adpcm->predict][0] + s_2 * f[adpcm->predict][1];
244  ds = s_0 * (double) (1<<adpcm->shift);
245 
246  di = ((int)ds+0x800) & 0xfffff000;
247  di = CLAMP(di,-32768,32767);
248 
249  four_bit[i] = (short)di;
250 
251  di = di >> adpcm->shift;
252  s_2 = s_1;
253  s_1 = (double) di - s_0;
254  }
255 
256  for (int i=0;i<14;i++)
257  adpcm->sample[i] = ( ( four_bit[(i*2)+1] >> 8 ) & 0xf0 ) | ( ( four_bit[i*2] >> 12 ) & 0xf );
258 
259  set->ps_1 = s_1;
260  set->ps_2 = s_2;
261 }
AdpcmSetup
Definition: adpcm.h:17
AdpcmBlock
Definition: adpcm.c:31
stdio.h
stdlib.h