summaryrefslogtreecommitdiff
path: root/apps/codecs/demac/libdemac/predictor.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/demac/libdemac/predictor.c')
-rw-r--r--apps/codecs/demac/libdemac/predictor.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/apps/codecs/demac/libdemac/predictor.c b/apps/codecs/demac/libdemac/predictor.c
new file mode 100644
index 0000000000..ef72fedfbd
--- /dev/null
+++ b/apps/codecs/demac/libdemac/predictor.c
@@ -0,0 +1,196 @@
1/*
2
3libdemac - A Monkey's Audio decoder
4
5$Id:$
6
7Copyright (C) Dave Chapman 2007
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
22
23*/
24
25#include <inttypes.h>
26#include <string.h>
27
28#include "parser.h"
29#include "predictor.h"
30
31#include "vector_math32.h"
32
33/* Return 0 if x is zero, -1 if x is positive, 1 if x is negative */
34#define SIGN(x) (x) ? (((x) > 0) ? -1 : 1) : 0
35
36static const int32_t initial_coeffs[4] = {
37 360, 317, -109, 98
38};
39
40static void init_predictor(struct predictor_t* p)
41{
42 /* Zero the history buffers */
43 memset(p->historybuffer, 0, (PREDICTOR_ORDER*4) * sizeof(int32_t));
44 p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
45 p->delayB = p->historybuffer + PREDICTOR_ORDER*3;
46 p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
47 p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER;
48
49 /* Initialise and zero the co-efficients */
50 memcpy(p->coeffsA, initial_coeffs, sizeof(initial_coeffs));
51 memset(p->coeffsB, 0, sizeof(p->coeffsB));
52
53 p->filterA = 0;
54 p->filterB = 0;
55
56 p->lastA = 0;
57}
58
59static int do_predictor_decode(struct predictor_t* p, int32_t A, int32_t B)
60{
61 int32_t predictionA, predictionB, currentA;
62
63 p->delayA[0] = p->lastA;
64 p->delayA[-1] = p->delayA[0] - p->delayA[-1];
65
66 predictionA = scalarproduct4_rev32(p->coeffsA,p->delayA);
67
68 /* Apply a scaled first-order filter compression */
69 p->delayB[0] = B - ((p->filterB * 31) >> 5);
70 p->filterB = B;
71
72 p->delayB[-1] = p->delayB[0] - p->delayB[-1];
73
74 predictionB = scalarproduct5_rev32(p->coeffsB,p->delayB);
75
76 currentA = A + ((predictionA + (predictionB >> 1)) >> 10);
77
78 p->adaptcoeffsA[0] = SIGN(p->delayA[0]);
79 p->adaptcoeffsA[-1] = SIGN(p->delayA[-1]);
80
81 p->adaptcoeffsB[0] = SIGN(p->delayB[0]);
82 p->adaptcoeffsB[-1] = SIGN(p->delayB[-1]);
83
84 if (A > 0)
85 {
86 vector_sub4_rev32(p->coeffsA, p->adaptcoeffsA);
87 vector_sub5_rev32(p->coeffsB, p->adaptcoeffsB);
88 }
89 else if (A < 0)
90 {
91 vector_add4_rev32(p->coeffsA, p->adaptcoeffsA);
92 vector_add5_rev32(p->coeffsB, p->adaptcoeffsB);
93 }
94
95 p->delayA++;
96 p->delayB++;
97 p->adaptcoeffsA++;
98 p->adaptcoeffsB++;
99
100 /* Have we filled the history buffer? */
101 if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) {
102 memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4),
103 (PREDICTOR_ORDER*4) * sizeof(int32_t));
104 p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
105 p->delayB = p->historybuffer + PREDICTOR_ORDER*3;
106 p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
107 p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER;
108 }
109
110 p->lastA = currentA;
111 p->filterA = currentA + ((p->filterA * 31) >> 5);
112
113 return p->filterA;
114}
115
116static int32_t X;
117
118void init_predictor_decoder(struct ape_ctx_t* ape_ctx)
119{
120 X = 0;
121
122 init_predictor(&ape_ctx->predictorY);
123 init_predictor(&ape_ctx->predictorX);
124}
125
126int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count) ICODE_ATTR;
127int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count)
128{
129 while (count--)
130 {
131 *decoded0 = do_predictor_decode(&ape_ctx->predictorY, *decoded0, X);
132 X = do_predictor_decode(&ape_ctx->predictorX, *decoded1, *(decoded0)++);
133 *(decoded1++) = X;
134 }
135
136 return 0;
137}
138
139int predictor_decode_mono(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int count)
140{
141 struct predictor_t* p = &ape_ctx->predictorY;
142 int32_t predictionA, currentA, A;
143
144 currentA = p->lastA;
145
146 while (count--)
147 {
148 A = *decoded0;
149
150 p->delayA[0] = currentA;
151 p->delayA[-1] = p->delayA[0] - p->delayA[-1];
152
153 predictionA = (p->delayA[0] * p->coeffsA[0]) +
154 (p->delayA[-1] * p->coeffsA[1]) +
155 (p->delayA[-2] * p->coeffsA[2]) +
156 (p->delayA[-3] * p->coeffsA[3]);
157
158 currentA = A + (predictionA >> 10);
159
160 p->adaptcoeffsA[0] = SIGN(p->delayA[0]);
161 p->adaptcoeffsA[-1] = SIGN(p->delayA[-1]);
162
163 if (A > 0)
164 {
165 p->coeffsA[0] -= p->adaptcoeffsA[0];
166 p->coeffsA[1] -= p->adaptcoeffsA[-1];
167 p->coeffsA[2] -= p->adaptcoeffsA[-2];
168 p->coeffsA[3] -= p->adaptcoeffsA[-3];
169 }
170 else if (A < 0)
171 {
172 p->coeffsA[0] += p->adaptcoeffsA[0];
173 p->coeffsA[1] += p->adaptcoeffsA[-1];
174 p->coeffsA[2] += p->adaptcoeffsA[-2];
175 p->coeffsA[3] += p->adaptcoeffsA[-3];
176 }
177
178 p->delayA++;
179 p->adaptcoeffsA++;
180
181 /* Have we filled the history buffer? */
182 if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) {
183 memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4),
184 (PREDICTOR_ORDER*4) * sizeof(int32_t));
185 p->delayA = p->historybuffer + PREDICTOR_ORDER*4;
186 p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2;
187 }
188
189 p->filterA = currentA + ((p->filterA * 31) >> 5);
190 *(decoded0++) = p->filterA;
191 }
192
193 p->lastA = currentA;
194
195 return 0;
196}