diff options
Diffstat (limited to 'lib/rbcodec/codecs/libayumi/ayumi.c')
-rw-r--r-- | lib/rbcodec/codecs/libayumi/ayumi.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libayumi/ayumi.c b/lib/rbcodec/codecs/libayumi/ayumi.c new file mode 100644 index 0000000000..2e0419f6cb --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/ayumi.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* Author: Peter Sovietov */ | ||
2 | |||
3 | #include <string.h> | ||
4 | #include <math.h> | ||
5 | #include "ayumi.h" | ||
6 | |||
7 | static const double AY_dac_table[] = { | ||
8 | 0.0, 0.0, | ||
9 | 0.00999465934234, 0.00999465934234, | ||
10 | 0.0144502937362, 0.0144502937362, | ||
11 | 0.0210574502174, 0.0210574502174, | ||
12 | 0.0307011520562, 0.0307011520562, | ||
13 | 0.0455481803616, 0.0455481803616, | ||
14 | 0.0644998855573, 0.0644998855573, | ||
15 | 0.107362478065, 0.107362478065, | ||
16 | 0.126588845655, 0.126588845655, | ||
17 | 0.20498970016, 0.20498970016, | ||
18 | 0.292210269322, 0.292210269322, | ||
19 | 0.372838941024, 0.372838941024, | ||
20 | 0.492530708782, 0.492530708782, | ||
21 | 0.635324635691, 0.635324635691, | ||
22 | 0.805584802014, 0.805584802014, | ||
23 | 1.0, 1.0 | ||
24 | }; | ||
25 | |||
26 | static const double YM_dac_table[] = { | ||
27 | 0.0, 0.0, | ||
28 | 0.00465400167849, 0.00772106507973, | ||
29 | 0.0109559777218, 0.0139620050355, | ||
30 | 0.0169985503929, 0.0200198367285, | ||
31 | 0.024368657969, 0.029694056611, | ||
32 | 0.0350652323186, 0.0403906309606, | ||
33 | 0.0485389486534, 0.0583352407111, | ||
34 | 0.0680552376593, 0.0777752346075, | ||
35 | 0.0925154497597, 0.111085679408, | ||
36 | 0.129747463188, 0.148485542077, | ||
37 | 0.17666895552, 0.211551079576, | ||
38 | 0.246387426566, 0.281101701381, | ||
39 | 0.333730067903, 0.400427252613, | ||
40 | 0.467383840696, 0.53443198291, | ||
41 | 0.635172045472, 0.75800717174, | ||
42 | 0.879926756695, 1.0 | ||
43 | }; | ||
44 | |||
45 | static void reset_segment(struct ayumi* ay); | ||
46 | |||
47 | double sqrt(double n) | ||
48 | { | ||
49 | double x0 = n; | ||
50 | double x1; | ||
51 | for (;;) { | ||
52 | x1 = x0 - (x0 * x0 - n) / (2 * x0); | ||
53 | double delta = (x1 - x0) / x0; | ||
54 | if (delta < .000001 && delta > -.000001) | ||
55 | return x1; | ||
56 | x0 = x1; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static int update_tone(struct ayumi* ay, int index) { | ||
61 | struct tone_channel* ch = &ay->channels[index]; | ||
62 | ch->tone_counter += 1; | ||
63 | if (ch->tone_counter >= ch->tone_period) { | ||
64 | ch->tone_counter = 0; | ||
65 | ch->tone ^= 1; | ||
66 | } | ||
67 | return ch->tone; | ||
68 | } | ||
69 | |||
70 | static int update_noise(struct ayumi* ay) { | ||
71 | int bit0x3; | ||
72 | ay->noise_counter += 1; | ||
73 | if (ay->noise_counter >= (ay->noise_period << 1)) { | ||
74 | ay->noise_counter = 0; | ||
75 | bit0x3 = ((ay->noise ^ (ay->noise >> 3)) & 1); | ||
76 | ay->noise = (ay->noise >> 1) | (bit0x3 << 16); | ||
77 | } | ||
78 | return ay->noise & 1; | ||
79 | } | ||
80 | |||
81 | static void slide_up(struct ayumi* ay) { | ||
82 | ay->envelope += 1; | ||
83 | if (ay->envelope > 31) { | ||
84 | ay->envelope_segment ^= 1; | ||
85 | reset_segment(ay); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void slide_down(struct ayumi* ay) { | ||
90 | ay->envelope -= 1; | ||
91 | if (ay->envelope < 0) { | ||
92 | ay->envelope_segment ^= 1; | ||
93 | reset_segment(ay); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static void hold_top(struct ayumi* ay) { | ||
98 | (void) ay; | ||
99 | } | ||
100 | |||
101 | static void hold_bottom(struct ayumi* ay) { | ||
102 | (void) ay; | ||
103 | } | ||
104 | |||
105 | static void (* const Envelopes[][2])(struct ayumi*) = { | ||
106 | {slide_down, hold_bottom}, | ||
107 | {slide_down, hold_bottom}, | ||
108 | {slide_down, hold_bottom}, | ||
109 | {slide_down, hold_bottom}, | ||
110 | {slide_up, hold_bottom}, | ||
111 | {slide_up, hold_bottom}, | ||
112 | {slide_up, hold_bottom}, | ||
113 | {slide_up, hold_bottom}, | ||
114 | {slide_down, slide_down}, | ||
115 | {slide_down, hold_bottom}, | ||
116 | {slide_down, slide_up}, | ||
117 | {slide_down, hold_top}, | ||
118 | {slide_up, slide_up}, | ||
119 | {slide_up, hold_top}, | ||
120 | {slide_up, slide_down}, | ||
121 | {slide_up, hold_bottom} | ||
122 | }; | ||
123 | |||
124 | static void reset_segment(struct ayumi* ay) { | ||
125 | if (Envelopes[ay->envelope_shape][ay->envelope_segment] == slide_down | ||
126 | || Envelopes[ay->envelope_shape][ay->envelope_segment] == hold_top) { | ||
127 | ay->envelope = 31; | ||
128 | return; | ||
129 | } | ||
130 | ay->envelope = 0; | ||
131 | } | ||
132 | |||
133 | int update_envelope(struct ayumi* ay) { | ||
134 | ay->envelope_counter += 1; | ||
135 | if (ay->envelope_counter >= ay->envelope_period) { | ||
136 | ay->envelope_counter = 0; | ||
137 | Envelopes[ay->envelope_shape][ay->envelope_segment](ay); | ||
138 | } | ||
139 | return ay->envelope; | ||
140 | } | ||
141 | |||
142 | static void update_mixer(struct ayumi* ay) { | ||
143 | int i; | ||
144 | int out; | ||
145 | int noise = update_noise(ay); | ||
146 | int envelope = update_envelope(ay); | ||
147 | ay->left = 0; | ||
148 | ay->right = 0; | ||
149 | for (i = 0; i < TONE_CHANNELS; i += 1) { | ||
150 | out = (update_tone(ay, i) | ay->channels[i].t_off) & (noise | ay->channels[i].n_off); | ||
151 | out *= ay->channels[i].e_on ? envelope : ay->channels[i].volume * 2 + 1; | ||
152 | ay->left += ay->dac_table[out] * ay->channels[i].pan_left; | ||
153 | ay->right += ay->dac_table[out] * ay->channels[i].pan_right; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr) { | ||
158 | int i; | ||
159 | memset(ay, 0, sizeof(struct ayumi)); | ||
160 | ay->step = clock_rate / (sr * 8 * DECIMATE_FACTOR); | ||
161 | ay->dac_table = is_ym ? YM_dac_table : AY_dac_table; | ||
162 | ay->noise = 1; | ||
163 | ayumi_set_envelope(ay, 1); | ||
164 | for (i = 0; i < TONE_CHANNELS; i += 1) { | ||
165 | ayumi_set_tone(ay, i, 1); | ||
166 | } | ||
167 | return ay->step < 1; | ||
168 | } | ||
169 | |||
170 | void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp) { | ||
171 | if (is_eqp) { | ||
172 | ay->channels[index].pan_left = sqrt(1 - pan); | ||
173 | ay->channels[index].pan_right = sqrt(pan); | ||
174 | } else { | ||
175 | ay->channels[index].pan_left = 1 - pan; | ||
176 | ay->channels[index].pan_right = pan; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | void ayumi_set_tone(struct ayumi* ay, int index, int period) { | ||
181 | period &= 0xfff; | ||
182 | ay->channels[index].tone_period = (period == 0) | period; | ||
183 | } | ||
184 | |||
185 | void ayumi_set_noise(struct ayumi* ay, int period) { | ||
186 | ay->noise_period = period & 0x1f; | ||
187 | } | ||
188 | |||
189 | void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on) { | ||
190 | ay->channels[index].t_off = t_off & 1; | ||
191 | ay->channels[index].n_off = n_off & 1; | ||
192 | ay->channels[index].e_on = e_on; | ||
193 | } | ||
194 | |||
195 | void ayumi_set_volume(struct ayumi* ay, int index, int volume) { | ||
196 | ay->channels[index].volume = volume & 0xf; | ||
197 | } | ||
198 | |||
199 | void ayumi_set_envelope(struct ayumi* ay, int period) { | ||
200 | period &= 0xffff; | ||
201 | ay->envelope_period = (period == 0) | period; | ||
202 | } | ||
203 | |||
204 | void ayumi_set_envelope_shape(struct ayumi* ay, int shape) { | ||
205 | ay->envelope_shape = shape & 0xf; | ||
206 | ay->envelope_counter = 0; | ||
207 | ay->envelope_segment = 0; | ||
208 | reset_segment(ay); | ||
209 | } | ||
210 | |||
211 | static double decimate(double* x) { | ||
212 | double y = -0.0000046183113992051936 * (x[1] + x[191]) + | ||
213 | -0.00001117761640887225 * (x[2] + x[190]) + | ||
214 | -0.000018610264502005432 * (x[3] + x[189]) + | ||
215 | -0.000025134586135631012 * (x[4] + x[188]) + | ||
216 | -0.000028494281690666197 * (x[5] + x[187]) + | ||
217 | -0.000026396828793275159 * (x[6] + x[186]) + | ||
218 | -0.000017094212558802156 * (x[7] + x[185]) + | ||
219 | 0.000023798193576966866 * (x[9] + x[183]) + | ||
220 | 0.000051281160242202183 * (x[10] + x[182]) + | ||
221 | 0.00007762197826243427 * (x[11] + x[181]) + | ||
222 | 0.000096759426664120416 * (x[12] + x[180]) + | ||
223 | 0.00010240229300393402 * (x[13] + x[179]) + | ||
224 | 0.000089344614218077106 * (x[14] + x[178]) + | ||
225 | 0.000054875700118949183 * (x[15] + x[177]) + | ||
226 | -0.000069839082210680165 * (x[17] + x[175]) + | ||
227 | -0.0001447966132360757 * (x[18] + x[174]) + | ||
228 | -0.00021158452917708308 * (x[19] + x[173]) + | ||
229 | -0.00025535069106550544 * (x[20] + x[172]) + | ||
230 | -0.00026228714374322104 * (x[21] + x[171]) + | ||
231 | -0.00022258805927027799 * (x[22] + x[170]) + | ||
232 | -0.00013323230495695704 * (x[23] + x[169]) + | ||
233 | 0.00016182578767055206 * (x[25] + x[167]) + | ||
234 | 0.00032846175385096581 * (x[26] + x[166]) + | ||
235 | 0.00047045611576184863 * (x[27] + x[165]) + | ||
236 | 0.00055713851457530944 * (x[28] + x[164]) + | ||
237 | 0.00056212565121518726 * (x[29] + x[163]) + | ||
238 | 0.00046901918553962478 * (x[30] + x[162]) + | ||
239 | 0.00027624866838952986 * (x[31] + x[161]) + | ||
240 | -0.00032564179486838622 * (x[33] + x[159]) + | ||
241 | -0.00065182310286710388 * (x[34] + x[158]) + | ||
242 | -0.00092127787309319298 * (x[35] + x[157]) + | ||
243 | -0.0010772534348943575 * (x[36] + x[156]) + | ||
244 | -0.0010737727700273478 * (x[37] + x[155]) + | ||
245 | -0.00088556645390392634 * (x[38] + x[154]) + | ||
246 | -0.00051581896090765534 * (x[39] + x[153]) + | ||
247 | 0.00059548767193795277 * (x[41] + x[151]) + | ||
248 | 0.0011803558710661009 * (x[42] + x[150]) + | ||
249 | 0.0016527320270369871 * (x[43] + x[149]) + | ||
250 | 0.0019152679330965555 * (x[44] + x[148]) + | ||
251 | 0.0018927324805381538 * (x[45] + x[147]) + | ||
252 | 0.0015481870327877937 * (x[46] + x[146]) + | ||
253 | 0.00089470695834941306 * (x[47] + x[145]) + | ||
254 | -0.0010178225878206125 * (x[49] + x[143]) + | ||
255 | -0.0020037400552054292 * (x[50] + x[142]) + | ||
256 | -0.0027874356824117317 * (x[51] + x[141]) + | ||
257 | -0.003210329988021943 * (x[52] + x[140]) + | ||
258 | -0.0031540624117984395 * (x[53] + x[139]) + | ||
259 | -0.0025657163651900345 * (x[54] + x[138]) + | ||
260 | -0.0014750752642111449 * (x[55] + x[137]) + | ||
261 | 0.0016624165446378462 * (x[57] + x[135]) + | ||
262 | 0.0032591192839069179 * (x[58] + x[134]) + | ||
263 | 0.0045165685815867747 * (x[59] + x[133]) + | ||
264 | 0.0051838984346123896 * (x[60] + x[132]) + | ||
265 | 0.0050774264697459933 * (x[61] + x[131]) + | ||
266 | 0.0041192521414141585 * (x[62] + x[130]) + | ||
267 | 0.0023628575417966491 * (x[63] + x[129]) + | ||
268 | -0.0026543507866759182 * (x[65] + x[127]) + | ||
269 | -0.0051990251084333425 * (x[66] + x[126]) + | ||
270 | -0.0072020238234656924 * (x[67] + x[125]) + | ||
271 | -0.0082672928192007358 * (x[68] + x[124]) + | ||
272 | -0.0081033739572956287 * (x[69] + x[123]) + | ||
273 | -0.006583111539570221 * (x[70] + x[122]) + | ||
274 | -0.0037839040415292386 * (x[71] + x[121]) + | ||
275 | 0.0042781252851152507 * (x[73] + x[119]) + | ||
276 | 0.0084176358598320178 * (x[74] + x[118]) + | ||
277 | 0.01172566057463055 * (x[75] + x[117]) + | ||
278 | 0.013550476647788672 * (x[76] + x[116]) + | ||
279 | 0.013388189369997496 * (x[77] + x[115]) + | ||
280 | 0.010979501242341259 * (x[78] + x[114]) + | ||
281 | 0.006381274941685413 * (x[79] + x[113]) + | ||
282 | -0.007421229604153888 * (x[81] + x[111]) + | ||
283 | -0.01486456304340213 * (x[82] + x[110]) + | ||
284 | -0.021143584622178104 * (x[83] + x[109]) + | ||
285 | -0.02504275058758609 * (x[84] + x[108]) + | ||
286 | -0.025473530942547201 * (x[85] + x[107]) + | ||
287 | -0.021627310017882196 * (x[86] + x[106]) + | ||
288 | -0.013104323383225543 * (x[87] + x[105]) + | ||
289 | 0.017065133989980476 * (x[89] + x[103]) + | ||
290 | 0.036978919264451952 * (x[90] + x[102]) + | ||
291 | 0.05823318062093958 * (x[91] + x[101]) + | ||
292 | 0.079072012081405949 * (x[92] + x[100]) + | ||
293 | 0.097675998716952317 * (x[93] + x[99]) + | ||
294 | 0.11236045936950932 * (x[94] + x[98]) + | ||
295 | 0.12176343577287731 * (x[95] + x[97]) + | ||
296 | 0.125 * x[96]; | ||
297 | memcpy(&x[FIR_SIZE - DECIMATE_FACTOR], x, DECIMATE_FACTOR * sizeof(double)); | ||
298 | return y; | ||
299 | } | ||
300 | |||
301 | void ayumi_process(struct ayumi* ay) { | ||
302 | int i; | ||
303 | double y1; | ||
304 | double* c_left = ay->interpolator_left.c; | ||
305 | double* y_left = ay->interpolator_left.y; | ||
306 | double* c_right = ay->interpolator_right.c; | ||
307 | double* y_right = ay->interpolator_right.y; | ||
308 | double* fir_left = &ay->fir_left[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; | ||
309 | double* fir_right = &ay->fir_right[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; | ||
310 | ay->fir_index = (ay->fir_index + 1) % (FIR_SIZE / DECIMATE_FACTOR - 1); | ||
311 | for (i = DECIMATE_FACTOR - 1; i >= 0; i -= 1) { | ||
312 | ay->x += ay->step; | ||
313 | if (ay->x >= 1) { | ||
314 | ay->x -= 1; | ||
315 | y_left[0] = y_left[1]; | ||
316 | y_left[1] = y_left[2]; | ||
317 | y_left[2] = y_left[3]; | ||
318 | y_right[0] = y_right[1]; | ||
319 | y_right[1] = y_right[2]; | ||
320 | y_right[2] = y_right[3]; | ||
321 | update_mixer(ay); | ||
322 | y_left[3] = ay->left; | ||
323 | y_right[3] = ay->right; | ||
324 | y1 = y_left[2] - y_left[0]; | ||
325 | c_left[0] = 0.5 * y_left[1] + 0.25 * (y_left[0] + y_left[2]); | ||
326 | c_left[1] = 0.5 * y1; | ||
327 | c_left[2] = 0.25 * (y_left[3] - y_left[1] - y1); | ||
328 | y1 = y_right[2] - y_right[0]; | ||
329 | c_right[0] = 0.5 * y_right[1] + 0.25 * (y_right[0] + y_right[2]); | ||
330 | c_right[1] = 0.5 * y1; | ||
331 | c_right[2] = 0.25 * (y_right[3] - y_right[1] - y1); | ||
332 | } | ||
333 | fir_left[i] = (c_left[2] * ay->x + c_left[1]) * ay->x + c_left[0]; | ||
334 | fir_right[i] = (c_right[2] * ay->x + c_right[1]) * ay->x + c_right[0]; | ||
335 | } | ||
336 | ay->left = decimate(fir_left); | ||
337 | ay->right = decimate(fir_right); | ||
338 | } | ||
339 | |||
340 | void ayumi_seek(struct ayumi* ay) { | ||
341 | int i; | ||
342 | for (i = DECIMATE_FACTOR - 1; i >= 0; i -= 1) { | ||
343 | ay->x += ay->step; | ||
344 | if (ay->x >= 1) { | ||
345 | ay->x -= 1; | ||
346 | update_mixer(ay); | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static double dc_filter(struct dc_filter* dc, int index, double x) { | ||
352 | dc->sum += -dc->delay[index] + x; | ||
353 | dc->delay[index] = x; | ||
354 | return x - dc->sum / DC_FILTER_SIZE; | ||
355 | } | ||
356 | |||
357 | void ayumi_remove_dc(struct ayumi* ay) { | ||
358 | ay->left = dc_filter(&ay->dc_left, ay->dc_index, ay->left); | ||
359 | ay->right = dc_filter(&ay->dc_right, ay->dc_index, ay->right); | ||
360 | ay->dc_index = (ay->dc_index + 1) & (DC_FILTER_SIZE - 1); | ||
361 | } | ||