diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libasap/apokeysnd.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libasap/apokeysnd.c')
-rw-r--r-- | lib/rbcodec/codecs/libasap/apokeysnd.c | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libasap/apokeysnd.c b/lib/rbcodec/codecs/libasap/apokeysnd.c new file mode 100644 index 0000000000..811e2f9b4a --- /dev/null +++ b/lib/rbcodec/codecs/libasap/apokeysnd.c | |||
@@ -0,0 +1,599 @@ | |||
1 | /* | ||
2 | * apokeysnd.c - another POKEY sound emulator | ||
3 | * | ||
4 | * Copyright (C) 2007-2010 Piotr Fusik | ||
5 | * | ||
6 | * This file is part of ASAP (Another Slight Atari Player), | ||
7 | * see http://asap.sourceforge.net | ||
8 | * | ||
9 | * ASAP is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published | ||
11 | * by the Free Software Foundation; either version 2 of the License, | ||
12 | * or (at your option) any later version. | ||
13 | * | ||
14 | * ASAP is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty | ||
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
17 | * See the GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with ASAP; if not, write to the Free Software Foundation, Inc., | ||
21 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | */ | ||
23 | |||
24 | #include "asap_internal.h" | ||
25 | |||
26 | #define ULTRASOUND_CYCLES 112 | ||
27 | |||
28 | #define MUTE_FREQUENCY 1 | ||
29 | #define MUTE_INIT 2 | ||
30 | #define MUTE_USER 4 | ||
31 | |||
32 | CONST_ARRAY(byte, poly4_lookup) | ||
33 | 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1 | ||
34 | END_CONST_ARRAY; | ||
35 | CONST_ARRAY(byte, poly5_lookup) | ||
36 | 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, | ||
37 | 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1 | ||
38 | END_CONST_ARRAY; | ||
39 | |||
40 | PRIVATE FUNC(void, PokeySound_InitializeChip, (P(PokeyState PTR, pst))) | ||
41 | { | ||
42 | pst _ audctl = 0; | ||
43 | pst _ init = FALSE; | ||
44 | pst _ poly_index = 15 * 31 * 131071; | ||
45 | pst _ div_cycles = 28; | ||
46 | pst _ mute1 = MUTE_FREQUENCY | MUTE_USER; | ||
47 | pst _ mute2 = MUTE_FREQUENCY | MUTE_USER; | ||
48 | pst _ mute3 = MUTE_FREQUENCY | MUTE_USER; | ||
49 | pst _ mute4 = MUTE_FREQUENCY | MUTE_USER; | ||
50 | pst _ audf1 = 0; | ||
51 | pst _ audf2 = 0; | ||
52 | pst _ audf3 = 0; | ||
53 | pst _ audf4 = 0; | ||
54 | pst _ audc1 = 0; | ||
55 | pst _ audc2 = 0; | ||
56 | pst _ audc3 = 0; | ||
57 | pst _ audc4 = 0; | ||
58 | pst _ tick_cycle1 = NEVER; | ||
59 | pst _ tick_cycle2 = NEVER; | ||
60 | pst _ tick_cycle3 = NEVER; | ||
61 | pst _ tick_cycle4 = NEVER; | ||
62 | pst _ period_cycles1 = 28; | ||
63 | pst _ period_cycles2 = 28; | ||
64 | pst _ period_cycles3 = 28; | ||
65 | pst _ period_cycles4 = 28; | ||
66 | pst _ reload_cycles1 = 28; | ||
67 | pst _ reload_cycles3 = 28; | ||
68 | pst _ out1 = 0; | ||
69 | pst _ out2 = 0; | ||
70 | pst _ out3 = 0; | ||
71 | pst _ out4 = 0; | ||
72 | pst _ delta1 = 0; | ||
73 | pst _ delta2 = 0; | ||
74 | pst _ delta3 = 0; | ||
75 | pst _ delta4 = 0; | ||
76 | pst _ skctl = 3; | ||
77 | ZERO_ARRAY(pst _ delta_buffer); | ||
78 | } | ||
79 | |||
80 | FUNC(void, PokeySound_Initialize, (P(ASAP_State PTR, ast))) | ||
81 | { | ||
82 | V(int, i); | ||
83 | V(int, reg); | ||
84 | reg = 0x1ff; | ||
85 | for (i = 0; i < 511; i++) { | ||
86 | reg = ((((reg >> 5) ^ reg) & 1) << 8) + (reg >> 1); | ||
87 | ast _ poly9_lookup[i] = TO_BYTE(reg); | ||
88 | } | ||
89 | reg = 0x1ffff; | ||
90 | for (i = 0; i < 16385; i++) { | ||
91 | reg = ((((reg >> 5) ^ reg) & 0xff) << 9) + (reg >> 8); | ||
92 | ast _ poly17_lookup[i] = TO_BYTE(reg >> 1); | ||
93 | } | ||
94 | ast _ sample_offset = 0; | ||
95 | ast _ sample_index = 0; | ||
96 | ast _ samples = 0; | ||
97 | ast _ iir_acc_left = 0; | ||
98 | ast _ iir_acc_right = 0; | ||
99 | PokeySound_InitializeChip(ADDRESSOF ast _ base_pokey); | ||
100 | PokeySound_InitializeChip(ADDRESSOF ast _ extra_pokey); | ||
101 | } | ||
102 | |||
103 | #define DO_TICK(ch) \ | ||
104 | if (pst _ init) { \ | ||
105 | switch (pst _ audc##ch >> 4) { \ | ||
106 | case 10: \ | ||
107 | case 14: \ | ||
108 | pst _ out##ch ^= 1; \ | ||
109 | pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta##ch = -pst _ delta##ch; \ | ||
110 | break; \ | ||
111 | default: \ | ||
112 | break; \ | ||
113 | } \ | ||
114 | } \ | ||
115 | else { \ | ||
116 | V(int, poly) = cycle + pst _ poly_index - (ch - 1); \ | ||
117 | V(int, newout) = pst _ out##ch; \ | ||
118 | switch (pst _ audc##ch >> 4) { \ | ||
119 | case 0: \ | ||
120 | if (poly5_lookup[poly % 31] != 0) { \ | ||
121 | if ((pst _ audctl & 0x80) != 0) \ | ||
122 | newout = ast _ poly9_lookup[poly % 511] & 1; \ | ||
123 | else { \ | ||
124 | poly %= 131071; \ | ||
125 | newout = (ast _ poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \ | ||
126 | } \ | ||
127 | } \ | ||
128 | break; \ | ||
129 | case 2: \ | ||
130 | case 6: \ | ||
131 | newout ^= poly5_lookup[poly % 31]; \ | ||
132 | break; \ | ||
133 | case 4: \ | ||
134 | if (poly5_lookup[poly % 31] != 0) \ | ||
135 | newout = poly4_lookup[poly % 15]; \ | ||
136 | break; \ | ||
137 | case 8: \ | ||
138 | if ((pst _ audctl & 0x80) != 0) \ | ||
139 | newout = ast _ poly9_lookup[poly % 511] & 1; \ | ||
140 | else { \ | ||
141 | poly %= 131071; \ | ||
142 | newout = (ast _ poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \ | ||
143 | } \ | ||
144 | break; \ | ||
145 | case 10: \ | ||
146 | case 14: \ | ||
147 | newout ^= 1; \ | ||
148 | break; \ | ||
149 | case 12: \ | ||
150 | newout = poly4_lookup[poly % 15]; \ | ||
151 | break; \ | ||
152 | default: \ | ||
153 | break; \ | ||
154 | } \ | ||
155 | if (newout != pst _ out##ch) { \ | ||
156 | pst _ out##ch = newout; \ | ||
157 | pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta##ch = -pst _ delta##ch; \ | ||
158 | } \ | ||
159 | } | ||
160 | |||
161 | /* Fills delta_buffer up to current_cycle basing on current AUDF/AUDC/AUDCTL values. */ | ||
162 | PRIVATE FUNC(void, PokeySound_GenerateUntilCycle, (P(ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, current_cycle))) | ||
163 | { | ||
164 | for (;;) { | ||
165 | V(int, cycle) = current_cycle; | ||
166 | if (cycle > pst _ tick_cycle1) | ||
167 | cycle = pst _ tick_cycle1; | ||
168 | if (cycle > pst _ tick_cycle2) | ||
169 | cycle = pst _ tick_cycle2; | ||
170 | if (cycle > pst _ tick_cycle3) | ||
171 | cycle = pst _ tick_cycle3; | ||
172 | if (cycle > pst _ tick_cycle4) | ||
173 | cycle = pst _ tick_cycle4; | ||
174 | if (cycle == current_cycle) | ||
175 | break; | ||
176 | if (cycle == pst _ tick_cycle3) { | ||
177 | pst _ tick_cycle3 += pst _ period_cycles3; | ||
178 | if ((pst _ audctl & 4) != 0 && pst _ delta1 > 0 && pst _ mute1 == 0) | ||
179 | pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta1 = -pst _ delta1; | ||
180 | DO_TICK(3); | ||
181 | } | ||
182 | if (cycle == pst _ tick_cycle4) { | ||
183 | pst _ tick_cycle4 += pst _ period_cycles4; | ||
184 | if ((pst _ audctl & 8) != 0) | ||
185 | pst _ tick_cycle3 = cycle + pst _ reload_cycles3; | ||
186 | if ((pst _ audctl & 2) != 0 && pst _ delta2 > 0 && pst _ mute2 == 0) | ||
187 | pst _ delta_buffer[CYCLE_TO_SAMPLE(cycle)] += pst _ delta2 = -pst _ delta2; | ||
188 | DO_TICK(4); | ||
189 | } | ||
190 | if (cycle == pst _ tick_cycle1) { | ||
191 | pst _ tick_cycle1 += pst _ period_cycles1; | ||
192 | if ((pst _ skctl & 0x88) == 8) /* two-tone, sending 1 (i.e. timer1) */ | ||
193 | pst _ tick_cycle2 = cycle + pst _ period_cycles2; | ||
194 | DO_TICK(1); | ||
195 | } | ||
196 | if (cycle == pst _ tick_cycle2) { | ||
197 | pst _ tick_cycle2 += pst _ period_cycles2; | ||
198 | if ((pst _ audctl & 0x10) != 0) | ||
199 | pst _ tick_cycle1 = cycle + pst _ reload_cycles1; | ||
200 | else if ((pst _ skctl & 8) != 0) /* two-tone */ | ||
201 | pst _ tick_cycle1 = cycle + pst _ period_cycles1; | ||
202 | DO_TICK(2); | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | #ifdef APOKEYSND | ||
208 | |||
209 | #define CURRENT_CYCLE 0 | ||
210 | #define CURRENT_SAMPLE 0 | ||
211 | #define DO_STORE(reg) \ | ||
212 | if (data == pst _ reg) \ | ||
213 | break; \ | ||
214 | pst _ reg = data; | ||
215 | |||
216 | #else | ||
217 | |||
218 | #define CURRENT_CYCLE ast _ cycle | ||
219 | #define CURRENT_SAMPLE CYCLE_TO_SAMPLE(ast _ cycle) | ||
220 | #define DO_STORE(reg) \ | ||
221 | if (data == pst _ reg) \ | ||
222 | break; \ | ||
223 | PokeySound_GenerateUntilCycle(ast, pst, ast _ cycle); \ | ||
224 | pst _ reg = data; | ||
225 | |||
226 | #endif /* APOKEYSND */ | ||
227 | |||
228 | #define MUTE_CHANNEL(ch, cond, mask) \ | ||
229 | if (cond) { \ | ||
230 | pst _ mute##ch |= mask; \ | ||
231 | pst _ tick_cycle##ch = NEVER; \ | ||
232 | } \ | ||
233 | else { \ | ||
234 | pst _ mute##ch &= ~mask; \ | ||
235 | if (pst _ tick_cycle##ch == NEVER && pst _ mute##ch == 0) \ | ||
236 | pst _ tick_cycle##ch = CURRENT_CYCLE; \ | ||
237 | } | ||
238 | |||
239 | #define DO_ULTRASOUND(ch) \ | ||
240 | MUTE_CHANNEL(ch, pst _ period_cycles##ch <= ULTRASOUND_CYCLES && (pst _ audc##ch >> 4 == 10 || pst _ audc##ch >> 4 == 14), MUTE_FREQUENCY) | ||
241 | |||
242 | #define DO_AUDC(ch) \ | ||
243 | DO_STORE(audc##ch); \ | ||
244 | if ((data & 0x10) != 0) { \ | ||
245 | data = (data & 0xf) << DELTA_SHIFT_POKEY; \ | ||
246 | if ((pst _ mute##ch & MUTE_USER) == 0) \ | ||
247 | pst _ delta_buffer[CURRENT_SAMPLE] \ | ||
248 | += pst _ delta##ch > 0 ? data - pst _ delta##ch : data; \ | ||
249 | pst _ delta##ch = data; \ | ||
250 | } \ | ||
251 | else { \ | ||
252 | data = (data & 0xf) << DELTA_SHIFT_POKEY; \ | ||
253 | DO_ULTRASOUND(ch); \ | ||
254 | if (pst _ delta##ch > 0) { \ | ||
255 | if ((pst _ mute##ch & MUTE_USER) == 0) \ | ||
256 | pst _ delta_buffer[CURRENT_SAMPLE] \ | ||
257 | += data - pst _ delta##ch; \ | ||
258 | pst _ delta##ch = data; \ | ||
259 | } \ | ||
260 | else \ | ||
261 | pst _ delta##ch = -data; \ | ||
262 | } \ | ||
263 | break; | ||
264 | |||
265 | #define DO_INIT(ch, cond) \ | ||
266 | MUTE_CHANNEL(ch, pst _ init && cond, MUTE_INIT) | ||
267 | |||
268 | FUNC(void, PokeySound_PutByte, (P(ASAP_State PTR, ast), P(int, addr), P(int, data))) | ||
269 | { | ||
270 | V(PokeyState PTR, pst) = (addr & ast _ extra_pokey_mask) != 0 | ||
271 | ? ADDRESSOF ast _ extra_pokey : ADDRESSOF ast _ base_pokey; | ||
272 | switch (addr & 0xf) { | ||
273 | case 0x00: | ||
274 | DO_STORE(audf1); | ||
275 | switch (pst _ audctl & 0x50) { | ||
276 | case 0x00: | ||
277 | pst _ period_cycles1 = pst _ div_cycles * (data + 1); | ||
278 | break; | ||
279 | case 0x10: | ||
280 | pst _ period_cycles2 = pst _ div_cycles * (data + 256 * pst _ audf2 + 1); | ||
281 | pst _ reload_cycles1 = pst _ div_cycles * (data + 1); | ||
282 | DO_ULTRASOUND(2); | ||
283 | break; | ||
284 | case 0x40: | ||
285 | pst _ period_cycles1 = data + 4; | ||
286 | break; | ||
287 | case 0x50: | ||
288 | pst _ period_cycles2 = data + 256 * pst _ audf2 + 7; | ||
289 | pst _ reload_cycles1 = data + 4; | ||
290 | DO_ULTRASOUND(2); | ||
291 | break; | ||
292 | } | ||
293 | DO_ULTRASOUND(1); | ||
294 | break; | ||
295 | case 0x01: | ||
296 | DO_AUDC(1) | ||
297 | case 0x02: | ||
298 | DO_STORE(audf2); | ||
299 | switch (pst _ audctl & 0x50) { | ||
300 | case 0x00: | ||
301 | case 0x40: | ||
302 | pst _ period_cycles2 = pst _ div_cycles * (data + 1); | ||
303 | break; | ||
304 | case 0x10: | ||
305 | pst _ period_cycles2 = pst _ div_cycles * (pst _ audf1 + 256 * data + 1); | ||
306 | break; | ||
307 | case 0x50: | ||
308 | pst _ period_cycles2 = pst _ audf1 + 256 * data + 7; | ||
309 | break; | ||
310 | } | ||
311 | DO_ULTRASOUND(2); | ||
312 | break; | ||
313 | case 0x03: | ||
314 | DO_AUDC(2) | ||
315 | case 0x04: | ||
316 | DO_STORE(audf3); | ||
317 | switch (pst _ audctl & 0x28) { | ||
318 | case 0x00: | ||
319 | pst _ period_cycles3 = pst _ div_cycles * (data + 1); | ||
320 | break; | ||
321 | case 0x08: | ||
322 | pst _ period_cycles4 = pst _ div_cycles * (data + 256 * pst _ audf4 + 1); | ||
323 | pst _ reload_cycles3 = pst _ div_cycles * (data + 1); | ||
324 | DO_ULTRASOUND(4); | ||
325 | break; | ||
326 | case 0x20: | ||
327 | pst _ period_cycles3 = data + 4; | ||
328 | break; | ||
329 | case 0x28: | ||
330 | pst _ period_cycles4 = data + 256 * pst _ audf4 + 7; | ||
331 | pst _ reload_cycles3 = data + 4; | ||
332 | DO_ULTRASOUND(4); | ||
333 | break; | ||
334 | } | ||
335 | DO_ULTRASOUND(3); | ||
336 | break; | ||
337 | case 0x05: | ||
338 | DO_AUDC(3) | ||
339 | case 0x06: | ||
340 | DO_STORE(audf4); | ||
341 | switch (pst _ audctl & 0x28) { | ||
342 | case 0x00: | ||
343 | case 0x20: | ||
344 | pst _ period_cycles4 = pst _ div_cycles * (data + 1); | ||
345 | break; | ||
346 | case 0x08: | ||
347 | pst _ period_cycles4 = pst _ div_cycles * (pst _ audf3 + 256 * data + 1); | ||
348 | break; | ||
349 | case 0x28: | ||
350 | pst _ period_cycles4 = pst _ audf3 + 256 * data + 7; | ||
351 | break; | ||
352 | } | ||
353 | DO_ULTRASOUND(4); | ||
354 | break; | ||
355 | case 0x07: | ||
356 | DO_AUDC(4) | ||
357 | case 0x08: | ||
358 | DO_STORE(audctl); | ||
359 | pst _ div_cycles = ((data & 1) != 0) ? 114 : 28; | ||
360 | /* TODO: tick_cycles */ | ||
361 | switch (data & 0x50) { | ||
362 | case 0x00: | ||
363 | pst _ period_cycles1 = pst _ div_cycles * (pst _ audf1 + 1); | ||
364 | pst _ period_cycles2 = pst _ div_cycles * (pst _ audf2 + 1); | ||
365 | break; | ||
366 | case 0x10: | ||
367 | pst _ period_cycles1 = pst _ div_cycles * 256; | ||
368 | pst _ period_cycles2 = pst _ div_cycles * (pst _ audf1 + 256 * pst _ audf2 + 1); | ||
369 | pst _ reload_cycles1 = pst _ div_cycles * (pst _ audf1 + 1); | ||
370 | break; | ||
371 | case 0x40: | ||
372 | pst _ period_cycles1 = pst _ audf1 + 4; | ||
373 | pst _ period_cycles2 = pst _ div_cycles * (pst _ audf2 + 1); | ||
374 | break; | ||
375 | case 0x50: | ||
376 | pst _ period_cycles1 = 256; | ||
377 | pst _ period_cycles2 = pst _ audf1 + 256 * pst _ audf2 + 7; | ||
378 | pst _ reload_cycles1 = pst _ audf1 + 4; | ||
379 | break; | ||
380 | } | ||
381 | DO_ULTRASOUND(1); | ||
382 | DO_ULTRASOUND(2); | ||
383 | switch (data & 0x28) { | ||
384 | case 0x00: | ||
385 | pst _ period_cycles3 = pst _ div_cycles * (pst _ audf3 + 1); | ||
386 | pst _ period_cycles4 = pst _ div_cycles * (pst _ audf4 + 1); | ||
387 | break; | ||
388 | case 0x08: | ||
389 | pst _ period_cycles3 = pst _ div_cycles * 256; | ||
390 | pst _ period_cycles4 = pst _ div_cycles * (pst _ audf3 + 256 * pst _ audf4 + 1); | ||
391 | pst _ reload_cycles3 = pst _ div_cycles * (pst _ audf3 + 1); | ||
392 | break; | ||
393 | case 0x20: | ||
394 | pst _ period_cycles3 = pst _ audf3 + 4; | ||
395 | pst _ period_cycles4 = pst _ div_cycles * (pst _ audf4 + 1); | ||
396 | break; | ||
397 | case 0x28: | ||
398 | pst _ period_cycles3 = 256; | ||
399 | pst _ period_cycles4 = pst _ audf3 + 256 * pst _ audf4 + 7; | ||
400 | pst _ reload_cycles3 = pst _ audf3 + 4; | ||
401 | break; | ||
402 | } | ||
403 | DO_ULTRASOUND(3); | ||
404 | DO_ULTRASOUND(4); | ||
405 | DO_INIT(1, (data & 0x40) == 0); | ||
406 | DO_INIT(2, (data & 0x50) != 0x50); | ||
407 | DO_INIT(3, (data & 0x20) == 0); | ||
408 | DO_INIT(4, (data & 0x28) != 0x28); | ||
409 | break; | ||
410 | case 0x09: | ||
411 | /* TODO: STIMER */ | ||
412 | break; | ||
413 | case 0x0f: | ||
414 | DO_STORE(skctl); | ||
415 | pst _ init = ((data & 3) == 0); | ||
416 | DO_INIT(1, (pst _ audctl & 0x40) == 0); | ||
417 | DO_INIT(2, (pst _ audctl & 0x50) != 0x50); | ||
418 | DO_INIT(3, (pst _ audctl & 0x20) == 0); | ||
419 | DO_INIT(4, (pst _ audctl & 0x28) != 0x28); | ||
420 | break; | ||
421 | default: | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | FUNC(int, PokeySound_GetRandom, (P(ASAP_State PTR, ast), P(int, addr), P(int, cycle))) | ||
427 | { | ||
428 | V(PokeyState PTR, pst) = (addr & ast _ extra_pokey_mask) != 0 | ||
429 | ? ADDRESSOF ast _ extra_pokey : ADDRESSOF ast _ base_pokey; | ||
430 | V(int, i); | ||
431 | if (pst _ init) | ||
432 | return 0xff; | ||
433 | i = cycle + pst _ poly_index; | ||
434 | if ((pst _ audctl & 0x80) != 0) | ||
435 | return ast _ poly9_lookup[i % 511]; | ||
436 | else { | ||
437 | V(int, j); | ||
438 | i %= 131071; | ||
439 | j = i >> 3; | ||
440 | i &= 7; | ||
441 | return ((ast _ poly17_lookup[j] >> i) + (ast _ poly17_lookup[j + 1] << (8 - i))) & 0xff; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | PRIVATE FUNC(void, end_frame, (P(ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, cycle_limit))) | ||
446 | { | ||
447 | V(int, m); | ||
448 | PokeySound_GenerateUntilCycle(ast, pst, cycle_limit); | ||
449 | pst _ poly_index += cycle_limit; | ||
450 | m = ((pst _ audctl & 0x80) != 0) ? 15 * 31 * 511 : 15 * 31 * 131071; | ||
451 | if (pst _ poly_index >= 2 * m) | ||
452 | pst _ poly_index -= m; | ||
453 | if (pst _ tick_cycle1 != NEVER) | ||
454 | pst _ tick_cycle1 -= cycle_limit; | ||
455 | if (pst _ tick_cycle2 != NEVER) | ||
456 | pst _ tick_cycle2 -= cycle_limit; | ||
457 | if (pst _ tick_cycle3 != NEVER) | ||
458 | pst _ tick_cycle3 -= cycle_limit; | ||
459 | if (pst _ tick_cycle4 != NEVER) | ||
460 | pst _ tick_cycle4 -= cycle_limit; | ||
461 | } | ||
462 | |||
463 | FUNC(void, PokeySound_StartFrame, (P(ASAP_State PTR, ast))) | ||
464 | { | ||
465 | ZERO_ARRAY(ast _ base_pokey.delta_buffer); | ||
466 | if (ast _ extra_pokey_mask != 0) | ||
467 | ZERO_ARRAY(ast _ extra_pokey.delta_buffer); | ||
468 | } | ||
469 | |||
470 | FUNC(void, PokeySound_EndFrame, (P(ASAP_State PTR, ast), P(int, current_cycle))) | ||
471 | { | ||
472 | V(int, clk) = ASAP_MAIN_CLOCK(ast); | ||
473 | end_frame(ast, ADDRESSOF ast _ base_pokey, current_cycle); | ||
474 | if (ast _ extra_pokey_mask != 0) | ||
475 | end_frame(ast, ADDRESSOF ast _ extra_pokey, current_cycle); | ||
476 | ast _ sample_offset += current_cycle * ASAP_SAMPLE_RATE; | ||
477 | ast _ sample_index = 0; | ||
478 | ast _ samples = TO_INT(ast _ sample_offset / clk); | ||
479 | ast _ sample_offset %= clk; | ||
480 | } | ||
481 | |||
482 | /* Fills buffer with samples from delta_buffer. */ | ||
483 | FUNC(int, PokeySound_Generate, (P(ASAP_State PTR, ast), P(BYTEARRAY, buffer), P(int, buffer_offset), P(int, blocks), P(ASAP_SampleFormat, format))) | ||
484 | { | ||
485 | V(int, i) = ast _ sample_index; | ||
486 | V(int, samples) = ast _ samples; | ||
487 | V(int, acc_left) = ast _ iir_acc_left; | ||
488 | V(int, acc_right) = ast _ iir_acc_right; | ||
489 | if (blocks < samples - i) | ||
490 | samples = i + blocks; | ||
491 | else | ||
492 | blocks = samples - i; | ||
493 | for (; i < samples; i++) { | ||
494 | #ifdef ACTIONSCRIPT | ||
495 | acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10); | ||
496 | var sample : Number = acc_left / 33553408; | ||
497 | buffer.writeFloat(sample); | ||
498 | if (ast.extra_pokey_mask != 0) { | ||
499 | acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10); | ||
500 | sample = acc_right / 33553408; | ||
501 | } | ||
502 | buffer.writeFloat(sample); | ||
503 | #else | ||
504 | V(int, sample); | ||
505 | acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10); | ||
506 | sample = acc_left >> 10; | ||
507 | #define STORE_SAMPLE \ | ||
508 | if (sample < -32767) \ | ||
509 | sample = -32767; \ | ||
510 | else if (sample > 32767) \ | ||
511 | sample = 32767; \ | ||
512 | switch (format) { \ | ||
513 | case ASAP_FORMAT_U8: \ | ||
514 | buffer[buffer_offset++] = CAST(byte) ((sample >> 8) + 128); \ | ||
515 | break; \ | ||
516 | case ASAP_FORMAT_S16_LE: \ | ||
517 | buffer[buffer_offset++] = TO_BYTE(sample); \ | ||
518 | buffer[buffer_offset++] = TO_BYTE(sample >> 8); \ | ||
519 | break; \ | ||
520 | case ASAP_FORMAT_S16_BE: \ | ||
521 | buffer[buffer_offset++] = TO_BYTE(sample >> 8); \ | ||
522 | buffer[buffer_offset++] = TO_BYTE(sample); \ | ||
523 | break; \ | ||
524 | } | ||
525 | STORE_SAMPLE; | ||
526 | if (ast _ extra_pokey_mask != 0) { | ||
527 | acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10); | ||
528 | sample = acc_right >> 10; | ||
529 | STORE_SAMPLE; | ||
530 | } | ||
531 | #endif /* ACTIONSCRIPT */ | ||
532 | } | ||
533 | if (i == ast _ samples) { | ||
534 | acc_left += ast _ base_pokey.delta_buffer[i]; | ||
535 | acc_right += ast _ extra_pokey.delta_buffer[i]; | ||
536 | } | ||
537 | ast _ sample_index = i; | ||
538 | ast _ iir_acc_left = acc_left; | ||
539 | ast _ iir_acc_right = acc_right; | ||
540 | #ifdef APOKEYSND | ||
541 | return buffer_offset; | ||
542 | #else | ||
543 | return blocks; | ||
544 | #endif | ||
545 | } | ||
546 | |||
547 | FUNC(abool, PokeySound_IsSilent, (P(CONST PokeyState PTR, pst))) | ||
548 | { | ||
549 | return ((pst _ audc1 | pst _ audc2 | pst _ audc3 | pst _ audc4) & 0xf) == 0; | ||
550 | } | ||
551 | |||
552 | FUNC(void, PokeySound_Mute, (P(CONST ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, mask))) | ||
553 | { | ||
554 | MUTE_CHANNEL(1, (mask & 1) != 0, MUTE_USER); | ||
555 | MUTE_CHANNEL(2, (mask & 2) != 0, MUTE_USER); | ||
556 | MUTE_CHANNEL(3, (mask & 4) != 0, MUTE_USER); | ||
557 | MUTE_CHANNEL(4, (mask & 8) != 0, MUTE_USER); | ||
558 | } | ||
559 | |||
560 | #ifdef APOKEYSND | ||
561 | |||
562 | static ASAP_State asap; | ||
563 | |||
564 | __declspec(dllexport) void APokeySound_Initialize(abool stereo) | ||
565 | { | ||
566 | asap.extra_pokey_mask = stereo ? 0x10 : 0; | ||
567 | PokeySound_Initialize(&asap); | ||
568 | PokeySound_Mute(&asap, &asap.base_pokey, 0); | ||
569 | PokeySound_Mute(&asap, &asap.extra_pokey, 0); | ||
570 | PokeySound_StartFrame(&asap); | ||
571 | } | ||
572 | |||
573 | __declspec(dllexport) void APokeySound_PutByte(int addr, int data) | ||
574 | { | ||
575 | PokeySound_PutByte(&asap, addr, data); | ||
576 | } | ||
577 | |||
578 | __declspec(dllexport) int APokeySound_GetRandom(int addr, int cycle) | ||
579 | { | ||
580 | return PokeySound_GetRandom(&asap, addr, cycle); | ||
581 | } | ||
582 | |||
583 | __declspec(dllexport) int APokeySound_Generate(int cycles, byte buffer[], ASAP_SampleFormat format) | ||
584 | { | ||
585 | int len; | ||
586 | PokeySound_EndFrame(&asap, cycles); | ||
587 | len = PokeySound_Generate(&asap, buffer, 0, asap.samples, format); | ||
588 | PokeySound_StartFrame(&asap); | ||
589 | return len; | ||
590 | } | ||
591 | |||
592 | __declspec(dllexport) void APokeySound_About(const char **name, const char **author, const char **description) | ||
593 | { | ||
594 | *name = "Another POKEY sound emulator, v" ASAP_VERSION; | ||
595 | *author = "Piotr Fusik, (C) " ASAP_YEARS; | ||
596 | *description = "Part of ASAP, http://asap.sourceforge.net"; | ||
597 | } | ||
598 | |||
599 | #endif /* APOKEYSND */ | ||