2 * apokeysnd.c - another POKEY sound emulator
4 * Copyright (C) 2007-2008 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 #if !defined(JAVA) && !defined(CSHARP)
28 #include "asap_internal.h"
30 #define memset ci->memset
31 #define ULTRASOUND_CYCLES 112
33 #define MUTE_FREQUENCY 1
37 CONST_LOOKUP(byte
, poly4_lookup
) =
38 { 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1 };
39 CONST_LOOKUP(byte
, poly5_lookup
) =
40 { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1,
41 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1 };
43 FILE_FUNC
void init_state(PokeyState PTR pst
)
47 PST poly_index
= 15 * 31 * 131071;
49 PST mute1
= MUTE_FREQUENCY
| MUTE_USER
;
50 PST mute2
= MUTE_FREQUENCY
| MUTE_USER
;
51 PST mute3
= MUTE_FREQUENCY
| MUTE_USER
;
52 PST mute4
= MUTE_FREQUENCY
| MUTE_USER
;
61 PST tick_cycle1
= NEVER
;
62 PST tick_cycle2
= NEVER
;
63 PST tick_cycle3
= NEVER
;
64 PST tick_cycle4
= NEVER
;
65 PST period_cycles1
= 28;
66 PST period_cycles2
= 28;
67 PST period_cycles3
= 28;
68 PST period_cycles4
= 28;
69 PST reload_cycles1
= 28;
70 PST reload_cycles3
= 28;
80 ZERO_ARRAY(PST delta_buffer
);
83 ASAP_FUNC
void PokeySound_Initialize(ASAP_State PTR ast
)
88 for (i
= 0; i
< 511; i
++) {
89 reg
= ((((reg
>> 5) ^ reg
) & 1) << 8) + (reg
>> 1);
90 AST poly9_lookup
[i
] = (byte
) reg
;
93 for (i
= 0; i
< 16385; i
++) {
94 reg
= ((((reg
>> 5) ^ reg
) & 0xff) << 9) + (reg
>> 8);
95 AST poly17_lookup
[i
] = (byte
) (reg
>> 1);
97 AST sample_offset
= 0;
100 AST iir_acc_left
= 0;
101 AST iir_acc_right
= 0;
102 init_state(ADDRESSOF AST base_pokey
);
103 init_state(ADDRESSOF AST extra_pokey
);
106 #define CYCLE_TO_SAMPLE(cycle) (((cycle) * ASAP_SAMPLE_RATE + AST sample_offset) / ASAP_MAIN_CLOCK)
108 #define DO_TICK(ch) \
110 switch (PST audc##ch >> 4) { \
114 PST delta_buffer[CYCLE_TO_SAMPLE(cycle)] += PST delta##ch = -PST delta##ch; \
121 int poly = cycle + PST poly_index - (ch - 1); \
122 int newout = PST out##ch; \
123 switch (PST audc##ch >> 4) { \
125 if (poly5_lookup[poly % 31] != 0) { \
126 if ((PST audctl & 0x80) != 0) \
127 newout = AST poly9_lookup[poly % 511] & 1; \
130 newout = (AST poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \
136 newout ^= poly5_lookup[poly % 31]; \
139 if (poly5_lookup[poly % 31] != 0) \
140 newout = poly4_lookup[poly % 15]; \
143 if ((PST audctl & 0x80) != 0) \
144 newout = AST poly9_lookup[poly % 511] & 1; \
147 newout = (AST poly17_lookup[poly >> 3] >> (poly & 7)) & 1; \
155 newout = poly4_lookup[poly % 15]; \
160 if (newout != PST out##ch) { \
161 PST out##ch = newout; \
162 PST delta_buffer[CYCLE_TO_SAMPLE(cycle)] += PST delta##ch = -PST delta##ch; \
166 FILE_FUNC
void generate(ASAP_State PTR ast
, PokeyState PTR pst
, int current_cycle
)
169 int cycle
= current_cycle
;
170 if (cycle
> PST tick_cycle1
)
171 cycle
= PST tick_cycle1
;
172 if (cycle
> PST tick_cycle2
)
173 cycle
= PST tick_cycle2
;
174 if (cycle
> PST tick_cycle3
)
175 cycle
= PST tick_cycle3
;
176 if (cycle
> PST tick_cycle4
)
177 cycle
= PST tick_cycle4
;
178 if (cycle
== current_cycle
)
180 if (cycle
== PST tick_cycle3
) {
181 PST tick_cycle3
+= PST period_cycles3
;
182 if ((PST audctl
& 4) != 0 && PST delta1
> 0 && PST mute1
== 0)
183 PST delta_buffer
[CYCLE_TO_SAMPLE(cycle
)] += PST delta1
= -PST delta1
;
186 if (cycle
== PST tick_cycle4
) {
187 PST tick_cycle4
+= PST period_cycles4
;
188 if ((PST audctl
& 8) != 0)
189 PST tick_cycle3
= cycle
+ PST reload_cycles3
;
190 if ((PST audctl
& 2) != 0 && PST delta2
> 0 && PST mute2
== 0)
191 PST delta_buffer
[CYCLE_TO_SAMPLE(cycle
)] += PST delta2
= -PST delta2
;
194 if (cycle
== PST tick_cycle1
) {
195 PST tick_cycle1
+= PST period_cycles1
;
196 if ((PST skctl
& 0x88) == 8)
197 PST tick_cycle2
= cycle
+ PST period_cycles2
;
200 if (cycle
== PST tick_cycle2
) {
201 PST tick_cycle2
+= PST period_cycles2
;
202 if ((PST audctl
& 0x10) != 0)
203 PST tick_cycle1
= cycle
+ PST reload_cycles1
;
204 else if ((PST skctl
& 8) != 0)
205 PST tick_cycle1
= cycle
+ PST period_cycles1
;
211 #define MUTE_CHANNEL(ch, cond, mask) \
213 PST mute##ch |= mask; \
214 PST tick_cycle##ch = NEVER; \
217 PST mute##ch &= ~mask; \
218 if (PST tick_cycle##ch == NEVER && PST mute##ch == 0) \
219 PST tick_cycle##ch = AST cycle; \
222 #define DO_ULTRASOUND(ch) \
223 MUTE_CHANNEL(ch, PST period_cycles##ch <= ULTRASOUND_CYCLES && (PST audc##ch >> 4 == 10 || PST audc##ch >> 4 == 14), MUTE_FREQUENCY)
225 #define DO_AUDC(ch) \
226 if (data == PST audc##ch) \
228 generate(ast, pst, AST cycle); \
229 PST audc##ch = data; \
230 if ((data & 0x10) != 0) { \
232 if ((PST mute##ch & MUTE_USER) == 0) \
233 PST delta_buffer[CYCLE_TO_SAMPLE(AST cycle)] \
234 += PST delta##ch > 0 ? data - PST delta##ch : data; \
235 PST delta##ch = data; \
240 if (PST delta##ch > 0) { \
241 if ((PST mute##ch & MUTE_USER) == 0) \
242 PST delta_buffer[CYCLE_TO_SAMPLE(AST cycle)] \
243 += data - PST delta##ch; \
244 PST delta##ch = data; \
247 PST delta##ch = -data; \
251 #define DO_INIT(ch, cond) \
252 MUTE_CHANNEL(ch, PST init && cond, MUTE_INIT)
254 ASAP_FUNC
void PokeySound_PutByte(ASAP_State PTR ast
, int addr
, int data
)
256 PokeyState PTR pst
= (addr
& AST extra_pokey_mask
) != 0
257 ? ADDRESSOF AST extra_pokey
: ADDRESSOF AST base_pokey
;
258 switch (addr
& 0xf) {
260 if (data
== PST audf1
)
262 generate(ast
, pst
, AST cycle
);
264 switch (PST audctl
& 0x50) {
266 PST period_cycles1
= PST div_cycles
* (data
+ 1);
269 PST period_cycles2
= PST div_cycles
* (data
+ 256 * PST audf2
+ 1);
270 PST reload_cycles1
= PST div_cycles
* (data
+ 1);
274 PST period_cycles1
= data
+ 4;
277 PST period_cycles2
= data
+ 256 * PST audf2
+ 7;
278 PST reload_cycles1
= data
+ 4;
287 if (data
== PST audf2
)
289 generate(ast
, pst
, AST cycle
);
291 switch (PST audctl
& 0x50) {
294 PST period_cycles2
= PST div_cycles
* (data
+ 1);
297 PST period_cycles2
= PST div_cycles
* (PST audf1
+ 256 * data
+ 1);
300 PST period_cycles2
= PST audf1
+ 256 * data
+ 7;
308 if (data
== PST audf3
)
310 generate(ast
, pst
, AST cycle
);
312 switch (PST audctl
& 0x28) {
314 PST period_cycles3
= PST div_cycles
* (data
+ 1);
317 PST period_cycles4
= PST div_cycles
* (data
+ 256 * PST audf4
+ 1);
318 PST reload_cycles3
= PST div_cycles
* (data
+ 1);
322 PST period_cycles3
= data
+ 4;
325 PST period_cycles4
= data
+ 256 * PST audf4
+ 7;
326 PST reload_cycles3
= data
+ 4;
335 if (data
== PST audf4
)
337 generate(ast
, pst
, AST cycle
);
339 switch (PST audctl
& 0x28) {
342 PST period_cycles4
= PST div_cycles
* (data
+ 1);
345 PST period_cycles4
= PST div_cycles
* (PST audf3
+ 256 * data
+ 1);
348 PST period_cycles4
= PST audf3
+ 256 * data
+ 7;
356 if (data
== PST audctl
)
358 generate(ast
, pst
, AST cycle
);
360 PST div_cycles
= ((data
& 1) != 0) ? 114 : 28;
361 /* TODO: tick_cycles */
362 switch (data
& 0x50) {
364 PST period_cycles1
= PST div_cycles
* (PST audf1
+ 1);
365 PST period_cycles2
= PST div_cycles
* (PST audf2
+ 1);
368 PST period_cycles1
= PST div_cycles
* 256;
369 PST period_cycles2
= PST div_cycles
* (PST audf1
+ 256 * PST audf2
+ 1);
370 PST reload_cycles1
= PST div_cycles
* (PST audf1
+ 1);
373 PST period_cycles1
= PST audf1
+ 4;
374 PST period_cycles2
= PST div_cycles
* (PST audf2
+ 1);
377 PST period_cycles1
= 256;
378 PST period_cycles2
= PST audf1
+ 256 * PST audf2
+ 7;
379 PST reload_cycles1
= PST audf1
+ 4;
384 switch (data
& 0x28) {
386 PST period_cycles3
= PST div_cycles
* (PST audf3
+ 1);
387 PST period_cycles4
= PST div_cycles
* (PST audf4
+ 1);
390 PST period_cycles3
= PST div_cycles
* 256;
391 PST period_cycles4
= PST div_cycles
* (PST audf3
+ 256 * PST audf4
+ 1);
392 PST reload_cycles3
= PST div_cycles
* (PST audf3
+ 1);
395 PST period_cycles3
= PST audf3
+ 4;
396 PST period_cycles4
= PST div_cycles
* (PST audf4
+ 1);
399 PST period_cycles3
= 256;
400 PST period_cycles4
= PST audf3
+ 256 * PST audf4
+ 7;
401 PST reload_cycles3
= PST audf3
+ 4;
412 PST init
= ((data
& 3) == 0);
413 DO_INIT(1, (PST audctl
& 0x40) == 0);
414 DO_INIT(2, (PST audctl
& 0x50) != 0x50);
415 DO_INIT(3, (PST audctl
& 0x20) == 0);
416 DO_INIT(4, (PST audctl
& 0x28) != 0x28);
423 ASAP_FUNC
int PokeySound_GetRandom(ASAP_State PTR ast
, int addr
)
425 PokeyState PTR pst
= (addr
& AST extra_pokey_mask
) != 0
426 ? ADDRESSOF AST extra_pokey
: ADDRESSOF AST base_pokey
;
430 i
= AST cycle
+ PST poly_index
;
431 if ((PST audctl
& 0x80) != 0)
432 return AST poly9_lookup
[i
% 511];
438 return ((AST poly17_lookup
[j
] >> i
) + (AST poly17_lookup
[j
+ 1] << (8 - i
))) & 0xff;
442 FILE_FUNC
void end_frame(ASAP_State PTR ast
, PokeyState PTR pst
, int cycle_limit
)
445 generate(ast
, pst
, cycle_limit
);
446 PST poly_index
+= cycle_limit
;
447 m
= ((PST audctl
& 0x80) != 0) ? 15 * 31 * 511 : 15 * 31 * 131071;
448 if (PST poly_index
>= 2 * m
)
450 if (PST tick_cycle1
!= NEVER
)
451 PST tick_cycle1
-= cycle_limit
;
452 if (PST tick_cycle2
!= NEVER
)
453 PST tick_cycle2
-= cycle_limit
;
454 if (PST tick_cycle3
!= NEVER
)
455 PST tick_cycle3
-= cycle_limit
;
456 if (PST tick_cycle4
!= NEVER
)
457 PST tick_cycle4
-= cycle_limit
;
460 ASAP_FUNC
void PokeySound_StartFrame(ASAP_State PTR ast
)
462 ZERO_ARRAY(AST base_pokey
.delta_buffer
);
463 if (AST extra_pokey_mask
!= 0)
464 ZERO_ARRAY(AST extra_pokey
.delta_buffer
);
467 ASAP_FUNC
void PokeySound_EndFrame(ASAP_State PTR ast
, int current_cycle
)
469 end_frame(ast
, ADDRESSOF AST base_pokey
, current_cycle
);
470 if (AST extra_pokey_mask
!= 0)
471 end_frame(ast
, ADDRESSOF AST extra_pokey
, current_cycle
);
472 AST sample_offset
+= current_cycle
* ASAP_SAMPLE_RATE
;
473 AST sample_index
= 0;
474 AST samples
= AST sample_offset
/ ASAP_MAIN_CLOCK
;
475 AST sample_offset
%= ASAP_MAIN_CLOCK
;
478 ASAP_FUNC
int PokeySound_Generate(ASAP_State PTR ast
, byte ARRAY buffer
, int buffer_offset
, int blocks
, ASAP_SampleFormat format
)
480 int i
= AST sample_index
;
481 int samples
= AST samples
;
482 int acc_left
= AST iir_acc_left
;
483 int acc_right
= AST iir_acc_right
;
484 if (blocks
< samples
- i
)
485 samples
= i
+ blocks
;
487 blocks
= samples
- i
;
488 for (; i
< samples
; i
++) {
490 acc_left
+= (AST base_pokey
.delta_buffer
[i
] << 20) - (acc_left
* 3 >> 10);
491 sample
= acc_left
>> 10;
492 #define STORE_SAMPLE \
493 if (sample < -32767) \
495 else if (sample > 32767) \
498 case ASAP_FORMAT_U8: \
499 buffer[buffer_offset++] = (byte) ((sample >> 8) + 128); \
501 case ASAP_FORMAT_S16_LE: \
502 buffer[buffer_offset++] = (byte) sample; \
503 buffer[buffer_offset++] = (byte) (sample >> 8); \
505 case ASAP_FORMAT_S16_BE: \
506 buffer[buffer_offset++] = (byte) (sample >> 8); \
507 buffer[buffer_offset++] = (byte) sample; \
511 if (AST extra_pokey_mask
!= 0) {
512 acc_right
+= (AST extra_pokey
.delta_buffer
[i
] << 20) - (acc_right
* 3 >> 10);
513 sample
= acc_right
>> 10;
517 if (i
== AST samples
) {
518 acc_left
+= AST base_pokey
.delta_buffer
[i
] << 20;
519 acc_right
+= AST extra_pokey
.delta_buffer
[i
] << 20;
521 AST sample_index
= i
;
522 AST iir_acc_left
= acc_left
;
523 AST iir_acc_right
= acc_right
;
527 ASAP_FUNC abool
PokeySound_IsSilent(const PokeyState PTR pst
)
529 return ((PST audc1
| PST audc2
| PST audc3
| PST audc4
) & 0xf) == 0;
532 ASAP_FUNC
void PokeySound_Mute(const ASAP_State PTR ast
, PokeyState PTR pst
, int mask
)
534 MUTE_CHANNEL(1, (mask
& 1) != 0, MUTE_USER
);
535 MUTE_CHANNEL(2, (mask
& 2) != 0, MUTE_USER
);
536 MUTE_CHANNEL(3, (mask
& 4) != 0, MUTE_USER
);
537 MUTE_CHANNEL(4, (mask
& 8) != 0, MUTE_USER
);