PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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
31typedef struct
32{
33 unsigned shift: 4 PACKED;
34 unsigned predict: 4 PACKED;
35 uint8_t flags;
36 uint8_t sample[14]; /* 4bits each */
38
39static void find_predict(AdpcmSetup *set, AdpcmBlock *adpcm, double *samples);
40static void pack(AdpcmSetup *set, AdpcmBlock *adpcm, const double *samples);
41
42
43AdpcmSetup *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
70int AdpcmDestroy(AdpcmSetup *set)
71{
72 free(set);
73 return(0);
74}
75
76int 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
157static 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
169static 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
229static 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}