Fix test_boost boost handling. Also show the number of loops per second.
[kugel-rb.git] / apps / codecs / libasap / apokeysnd.c
blobead611be5f41d5331020ab1753221e22e885ebdc
1 /*
2 * apokeysnd.c - another POKEY sound emulator
4 * Copyright (C) 2007-2009 Piotr Fusik
6 * This file is part of ASAP (Another Slight Atari Player),
7 * see http://asap.sourceforge.net
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.
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.
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
24 #include "asap_internal.h"
26 #define ULTRASOUND_CYCLES 112
28 #define MUTE_FREQUENCY 1
29 #define MUTE_INIT 2
30 #define MUTE_USER 4
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;
40 PRIVATE FUNC(void, PokeySound_InitializeChip, (P(PokeyState PTR, pst)))
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);
80 FUNC(void, PokeySound_Initialize, (P(ASAP_State PTR, ast)))
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);
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);
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);
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; \
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; \
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; \
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; \
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; \
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)))
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);
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);
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);
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);
207 #ifdef APOKEYSND
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;
216 #else
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;
226 #endif /* APOKEYSND */
228 #define MUTE_CHANNEL(ch, cond, mask) \
229 if (cond) { \
230 pst _ mute##ch |= mask; \
231 pst _ tick_cycle##ch = NEVER; \
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; \
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)
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; \
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; \
260 else \
261 pst _ delta##ch = -data; \
263 break;
265 #define DO_INIT(ch, cond) \
266 MUTE_CHANNEL(ch, pst _ init && cond, MUTE_INIT)
268 FUNC(void, PokeySound_PutByte, (P(ASAP_State PTR, ast), P(int, addr), P(int, data)))
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;
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;
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;
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;
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;
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;
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;
426 FUNC(int, PokeySound_GetRandom, (P(ASAP_State PTR, ast), P(int, addr), P(int, cycle)))
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;
445 PRIVATE FUNC(void, end_frame, (P(ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, cycle_limit)))
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;
463 FUNC(void, PokeySound_StartFrame, (P(ASAP_State PTR, ast)))
465 ZERO_ARRAY(ast _ base_pokey.delta_buffer);
466 if (ast _ extra_pokey_mask != 0)
467 ZERO_ARRAY(ast _ extra_pokey.delta_buffer);
470 FUNC(void, PokeySound_EndFrame, (P(ASAP_State PTR, ast), P(int, current_cycle)))
472 end_frame(ast, ADDRESSOF ast _ base_pokey, current_cycle);
473 if (ast _ extra_pokey_mask != 0)
474 end_frame(ast, ADDRESSOF ast _ extra_pokey, current_cycle);
475 ast _ sample_offset += current_cycle * ASAP_SAMPLE_RATE;
476 ast _ sample_index = 0;
477 ast _ samples = TO_INT(ast _ sample_offset / ASAP_MAIN_CLOCK);
478 ast _ sample_offset %= ASAP_MAIN_CLOCK;
481 /* Fills buffer with samples from delta_buffer. */
482 FUNC(int, PokeySound_Generate, (P(ASAP_State PTR, ast), P(BYTEARRAY, buffer), P(int, buffer_offset), P(int, blocks), P(ASAP_SampleFormat, format)))
484 V(int, i) = ast _ sample_index;
485 V(int, samples) = ast _ samples;
486 V(int, acc_left) = ast _ iir_acc_left;
487 V(int, acc_right) = ast _ iir_acc_right;
488 if (blocks < samples - i)
489 samples = i + blocks;
490 else
491 blocks = samples - i;
492 for (; i < samples; i++) {
493 #ifdef ACTIONSCRIPT
494 acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10);
495 var sample : Number = acc_left / 33553408;
496 buffer.writeFloat(sample);
497 if (ast.extra_pokey_mask != 0) {
498 acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10);
499 sample = acc_right / 33553408;
501 buffer.writeFloat(sample);
502 #else
503 V(int, sample);
504 acc_left += ast _ base_pokey.delta_buffer[i] - (acc_left * 3 >> 10);
505 sample = acc_left >> 10;
506 #define STORE_SAMPLE \
507 if (sample < -32767) \
508 sample = -32767; \
509 else if (sample > 32767) \
510 sample = 32767; \
511 switch (format) { \
512 case ASAP_FORMAT_U8: \
513 buffer[buffer_offset++] = CAST(byte) ((sample >> 8) + 128); \
514 break; \
515 case ASAP_FORMAT_S16_LE: \
516 buffer[buffer_offset++] = TO_BYTE(sample); \
517 buffer[buffer_offset++] = TO_BYTE(sample >> 8); \
518 break; \
519 case ASAP_FORMAT_S16_BE: \
520 buffer[buffer_offset++] = TO_BYTE(sample >> 8); \
521 buffer[buffer_offset++] = TO_BYTE(sample); \
522 break; \
524 STORE_SAMPLE;
525 if (ast _ extra_pokey_mask != 0) {
526 acc_right += ast _ extra_pokey.delta_buffer[i] - (acc_right * 3 >> 10);
527 sample = acc_right >> 10;
528 STORE_SAMPLE;
530 #endif /* ACTIONSCRIPT */
532 if (i == ast _ samples) {
533 acc_left += ast _ base_pokey.delta_buffer[i];
534 acc_right += ast _ extra_pokey.delta_buffer[i];
536 ast _ sample_index = i;
537 ast _ iir_acc_left = acc_left;
538 ast _ iir_acc_right = acc_right;
539 #ifdef APOKEYSND
540 return buffer_offset;
541 #else
542 return blocks;
543 #endif
546 FUNC(abool, PokeySound_IsSilent, (P(CONST PokeyState PTR, pst)))
548 return ((pst _ audc1 | pst _ audc2 | pst _ audc3 | pst _ audc4) & 0xf) == 0;
551 FUNC(void, PokeySound_Mute, (P(CONST ASAP_State PTR, ast), P(PokeyState PTR, pst), P(int, mask)))
553 MUTE_CHANNEL(1, (mask & 1) != 0, MUTE_USER);
554 MUTE_CHANNEL(2, (mask & 2) != 0, MUTE_USER);
555 MUTE_CHANNEL(3, (mask & 4) != 0, MUTE_USER);
556 MUTE_CHANNEL(4, (mask & 8) != 0, MUTE_USER);
559 #ifdef APOKEYSND
561 static ASAP_State asap;
563 __declspec(dllexport) void APokeySound_Initialize(abool stereo)
565 asap.extra_pokey_mask = stereo ? 0x10 : 0;
566 PokeySound_Initialize(&asap);
567 PokeySound_Mute(&asap, &asap.base_pokey, 0);
568 PokeySound_Mute(&asap, &asap.extra_pokey, 0);
569 PokeySound_StartFrame(&asap);
572 __declspec(dllexport) void APokeySound_PutByte(int addr, int data)
574 PokeySound_PutByte(&asap, addr, data);
577 __declspec(dllexport) int APokeySound_GetRandom(int addr, int cycle)
579 return PokeySound_GetRandom(&asap, addr, cycle);
582 __declspec(dllexport) int APokeySound_Generate(int cycles, byte buffer[], ASAP_SampleFormat format)
584 int len;
585 PokeySound_EndFrame(&asap, cycles);
586 len = PokeySound_Generate(&asap, buffer, 0, asap.samples, format);
587 PokeySound_StartFrame(&asap);
588 return len;
591 __declspec(dllexport) void APokeySound_About(const char **name, const char **author, const char **description)
593 *name = "Another POKEY sound emulator, v" ASAP_VERSION;
594 *author = "Piotr Fusik, (C) " ASAP_YEARS;
595 *description = "Part of ASAP, http://asap.sourceforge.net";
598 #endif /* APOKEYSND */