4 * Copyright (C) 2005-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"
29 #if !defined(JAVA) && !defined(CSHARP)
33 #define memcpy ci->memcpy
34 #define memcmp ci->memcmp
35 #define memset ci->memset
36 #define strcpy ci->strcpy
37 #define strcmp ci->strcmp
38 #define strstr ci->strcasestr
41 #define CMR_BASS_TABLE_OFFSET 0x70f
43 CONST_LOOKUP(byte
, cmr_bass_table
) = {
44 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E,
45 0x38, 0x35, (byte
) 0x88, 0x7F, 0x79, 0x73, 0x6C, 0x67,
46 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F,
47 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28,
48 0x25, 0x24, 0x21, 0x1F, 0x1E
51 ASAP_FUNC
int ASAP_GetByte(ASAP_State PTR ast
, int addr
)
53 switch (addr
& 0xff0f) {
55 return PokeySound_GetRandom(ast
, addr
);
57 if ((addr
& AST extra_pokey_mask
) != 0)
63 return AST scanline_number
>> 1;
65 return dGetByte(addr
);
69 ASAP_FUNC
void ASAP_PutByte(ASAP_State PTR ast
, int addr
, int data
)
71 if ((addr
>> 8) == 0xd2) {
72 if ((addr
& (AST extra_pokey_mask
+ 0xf)) == 0xe) {
73 AST irqst
|= data
^ 0xff;
74 #define SET_TIMER_IRQ(ch) \
75 if ((data & AST irqst & ch) != 0) { \
76 if (AST timer##ch##_cycle == NEVER) { \
77 int t = AST base_pokey.tick_cycle##ch; \
78 while (t < AST cycle) \
79 t += AST base_pokey.period_cycles##ch; \
80 AST timer##ch##_cycle = t; \
81 if (AST nearest_event_cycle > t) \
82 AST nearest_event_cycle = t; \
86 AST timer##ch##_cycle = NEVER;
92 PokeySound_PutByte(ast
, addr
, data
);
94 else if ((addr
& 0xff0f) == 0xd40a) {
95 if (AST cycle
<= AST next_scanline_cycle
- 8)
96 AST cycle
= AST next_scanline_cycle
- 8;
98 AST cycle
= AST next_scanline_cycle
+ 106;
101 dPutByte(addr
, data
);
106 CONST_LOOKUP(int, perframe2fastplay
) = { 312, 312 / 2, 312 / 3, 312 / 4 };
108 FILE_FUNC abool
load_native(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
109 const byte ARRAY module
, int module_len
, ASAP_OBX player
)
111 #if defined(JAVA) || defined(CSHARP)
115 int player_last_byte
;
117 if (UBYTE(module
[0]) != 0xff || UBYTE(module
[1]) != 0xff)
123 MODULE_INFO player
= player
.read();
124 MODULE_INFO player
+= player
.read() << 8;
125 player_last_byte
= player
.read();
126 player_last_byte
+= player
.read() << 8;
127 } catch (IOException e
) {
128 throw new RuntimeException();
130 #elif defined(CSHARP)
133 MODULE_INFO player
= player
.ReadByte();
134 MODULE_INFO player
+= player
.ReadByte() << 8;
135 player_last_byte
= player
.ReadByte();
136 player_last_byte
+= player
.ReadByte() << 8;
138 MODULE_INFO player
= UBYTE(player
[2]) + (UBYTE(player
[3]) << 8);
139 player_last_byte
= UBYTE(player
[4]) + (UBYTE(player
[5]) << 8);
141 MODULE_INFO music
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8);
142 if (MODULE_INFO music
<= player_last_byte
)
144 block_len
= UBYTE(module
[4]) + (UBYTE(module
[5]) << 8) + 1 - MODULE_INFO music
;
145 if (6 + block_len
!= module_len
) {
148 if (MODULE_INFO type
!= 'r' || 11 + block_len
> module_len
)
150 /* allow optional info for Raster Music Tracker */
151 info_addr
= UBYTE(module
[6 + block_len
]) + (UBYTE(module
[7 + block_len
]) << 8);
152 if (info_addr
!= MODULE_INFO music
+ block_len
)
154 info_len
= UBYTE(module
[8 + block_len
]) + (UBYTE(module
[9 + block_len
]) << 8) + 1 - info_addr
;
155 if (10 + block_len
+ info_len
!= module_len
)
159 COPY_ARRAY(AST memory
, MODULE_INFO music
, module
, 6, block_len
);
161 int addr
= MODULE_INFO player
;
165 i
= player
.read(AST memory
, addr
, player_last_byte
+ 1 - addr
);
166 } catch (IOException e
) {
167 throw new RuntimeException();
170 throw new RuntimeException();
172 } while (addr
<= player_last_byte
);
173 #elif defined(CSHARP)
174 int addr
= MODULE_INFO player
;
176 int i
= player
.Read(AST memory
, addr
, player_last_byte
+ 1 - addr
);
178 throw new Exception();
180 } while (addr
<= player_last_byte
);
182 COPY_ARRAY(AST memory
, MODULE_INFO player
, player
, 6, player_last_byte
+ 1 - MODULE_INFO player
);
191 } catch (IOException e
) {
192 throw new RuntimeException();
195 #elif defined(CSHARP)
202 FILE_FUNC
void set_song_duration(ASAP_ModuleInfo PTR module_info
, int player_calls
)
204 MODULE_INFO durations
[MODULE_INFO songs
] = (int) (player_calls
* MODULE_INFO fastplay
* 114000.0 / 1773447);
208 #define SEEN_THIS_CALL 1
209 #define SEEN_BEFORE 2
210 #define SEEN_REPEAT 3
212 FILE_FUNC
void parse_cmc_song(ASAP_ModuleInfo PTR module_info
, const byte ARRAY module
, int pos
)
214 int tempo
= UBYTE(module
[0x19]);
215 int player_calls
= 0;
216 int rep_start_pos
= 0;
219 NEW_ARRAY(byte
, seen
, 0x55);
221 while (pos
>= 0 && pos
< 0x55) {
225 if (pos
== rep_end_pos
&& rep_times
> 0) {
226 for (p1
= 0; p1
< 0x55; p1
++)
227 if (seen
[p1
] == SEEN_THIS_CALL
|| seen
[p1
] == SEEN_REPEAT
)
232 if (seen
[pos
] != 0) {
233 if (seen
[pos
] != SEEN_THIS_CALL
)
234 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
237 seen
[pos
] = SEEN_THIS_CALL
;
238 p1
= UBYTE(module
[0x206 + pos
]);
239 p2
= UBYTE(module
[0x25b + pos
]);
240 p3
= UBYTE(module
[0x2b0 + pos
]);
241 if (p1
== 0xfe || p2
== 0xfe || p3
== 0xfe) {
268 rep_end_pos
= pos
+ p2
;
273 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
276 p2
= rep_times
> 0 ? SEEN_REPEAT
: SEEN_BEFORE
;
277 for (p1
= 0; p1
< 0x55; p1
++)
278 if (seen
[p1
] == SEEN_THIS_CALL
)
279 seen
[p1
] = (byte
) p2
;
280 player_calls
+= tempo
<< 6;
283 set_song_duration(module_info
, player_calls
);
286 FILE_FUNC abool
parse_cmc(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
287 const byte ARRAY module
, int module_len
, abool cmr
)
291 if (module_len
< 0x306)
293 MODULE_INFO type
= cmr
? 'z' : 'c';
294 if (!load_native(ast
, module_info
, module
, module_len
, GET_OBX(cmc
)))
296 if (ast
!= NULL
&& cmr
)
297 COPY_ARRAY(AST memory
, 0x500 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, 0, sizeof(cmr_bass_table
));
298 /* auto-detect number of subsongs */
300 while (--last_pos
>= 0) {
301 if (UBYTE(module
[0x206 + last_pos
]) < 0xb0
302 || UBYTE(module
[0x25b + last_pos
]) < 0x40
303 || UBYTE(module
[0x2b0 + last_pos
]) < 0x40)
306 MODULE_INFO songs
= 0;
307 parse_cmc_song(module_info
, module
, 0);
308 for (pos
= 0; pos
< last_pos
&& MODULE_INFO songs
< MAX_SONGS
; pos
++)
309 if (UBYTE(module
[0x206 + pos
]) == 0x8f || UBYTE(module
[0x206 + pos
]) == 0xef)
310 parse_cmc_song(module_info
, module
, pos
+ 1);
314 FILE_FUNC
void parse_mpt_song(ASAP_ModuleInfo PTR module_info
, const byte ARRAY module
,
315 abool ARRAY global_seen
, int song_len
, int pos
)
317 int addr_to_offset
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) - 6;
318 int tempo
= UBYTE(module
[0x1cf]);
319 int player_calls
= 0;
320 NEW_ARRAY(byte
, seen
, 256);
321 NEW_ARRAY(int, pattern_offset
, 4);
322 NEW_ARRAY(int, blank_rows
, 4);
323 NEW_ARRAY(int, blank_rows_counter
, 4);
325 INIT_ARRAY(blank_rows
);
326 while (pos
< song_len
) {
330 if (seen
[pos
] != 0) {
331 if (seen
[pos
] != SEEN_THIS_CALL
)
332 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
335 seen
[pos
] = SEEN_THIS_CALL
;
336 global_seen
[pos
] = TRUE
;
337 i
= UBYTE(module
[0x1d0 + pos
* 2]);
339 pos
= UBYTE(module
[0x1d1 + pos
* 2]);
342 for (ch
= 3; ch
>= 0; ch
--) {
343 i
= UBYTE(module
[0x1c6 + ch
]) + (UBYTE(module
[0x1ca + ch
]) << 8) - addr_to_offset
;
344 i
= UBYTE(module
[i
+ pos
* 2]);
348 i
= UBYTE(module
[0x46 + i
]) + (UBYTE(module
[0x47 + i
]) << 8);
349 pattern_offset
[ch
] = i
== 0 ? 0 : i
- addr_to_offset
;
350 blank_rows_counter
[ch
] = 0;
354 for (i
= 0; i
< song_len
; i
++)
355 if (seen
[i
] == SEEN_THIS_CALL
)
356 seen
[i
] = SEEN_BEFORE
;
357 for (pattern_rows
= UBYTE(module
[0x1ce]); --pattern_rows
>= 0; ) {
358 for (ch
= 3; ch
>= 0; ch
--) {
359 if (pattern_offset
[ch
] == 0 || --blank_rows_counter
[ch
] >= 0)
362 i
= UBYTE(module
[pattern_offset
[ch
]++]);
363 if (i
< 0x40 || i
== 0xfe)
368 blank_rows
[ch
] = i
- 0x80;
379 blank_rows_counter
[ch
] = blank_rows
[ch
];
381 player_calls
+= tempo
;
385 if (player_calls
> 0)
386 set_song_duration(module_info
, player_calls
);
389 FILE_FUNC abool
parse_mpt(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
390 const byte ARRAY module
, int module_len
)
395 /* seen[i] == TRUE if the track position i has been processed */
396 NEW_ARRAY(abool
, global_seen
, 256);
397 if (module_len
< 0x1d0)
399 MODULE_INFO type
= 'm';
400 if (!load_native(ast
, module_info
, module
, module_len
, GET_OBX(mpt
)))
402 track0_addr
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) + 0x1ca;
403 if (UBYTE(module
[0x1c6]) + (UBYTE(module
[0x1ca]) << 8) != track0_addr
)
405 /* Calculate the length of the first track. Address of the second track minus
406 address of the first track equals the length of the first track in bytes.
407 Divide by two to get number of track positions. */
408 song_len
= (UBYTE(module
[0x1c7]) + (UBYTE(module
[0x1cb]) << 8) - track0_addr
) >> 1;
411 INIT_ARRAY(global_seen
);
412 MODULE_INFO songs
= 0;
413 for (pos
= 0; pos
< song_len
&& MODULE_INFO songs
< MAX_SONGS
; pos
++) {
414 if (!global_seen
[pos
]) {
415 MODULE_INFO song_pos
[MODULE_INFO songs
] = (byte
) pos
;
416 parse_mpt_song(module_info
, module
, global_seen
, song_len
, pos
);
419 return MODULE_INFO songs
!= 0;
422 CONST_LOOKUP(byte
, rmt_volume_silent
) = { 16, 8, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 };
424 FILE_FUNC
int rmt_instrument_frames(const byte ARRAY module
, int instrument
, int volume
, int volume_frame
, abool extra_pokey
)
426 int addr_to_offset
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) - 6;
427 int per_frame
= module
[0xc];
433 int volume_slide_depth
;
438 instrument
= UBYTE(module
[0xe]) + (UBYTE(module
[0xf]) << 8) - addr_to_offset
+ (instrument
<< 1);
439 if (module
[instrument
+ 1] == 0)
441 instrument
= UBYTE(module
[instrument
]) + (UBYTE(module
[instrument
+ 1]) << 8) - addr_to_offset
;
442 player_calls
= player_call
= volume_frame
* per_frame
;
443 index
= UBYTE(module
[instrument
]) + 1 + player_call
* 3;
444 index_end
= UBYTE(module
[instrument
+ 2]) + 3;
445 index_loop
= UBYTE(module
[instrument
+ 3]);
446 if (index_loop
>= index_end
)
447 return 0; /* error */
448 volume_slide_depth
= UBYTE(module
[instrument
+ 6]);
449 volume_min
= UBYTE(module
[instrument
+ 7]);
450 looping
= index
>= index_end
;
452 index
= (index
- index_end
) % (index_end
- index_loop
) + index_loop
;
455 int vol
= module
[instrument
+ index
];
458 if ((vol
& 0xf) >= rmt_volume_silent
[volume
])
459 player_calls
= player_call
+ 1;
462 } while (index
< index_end
);
464 if (volume_slide_depth
== 0)
465 return player_calls
/ per_frame
;
470 if (index
>= index_end
) {
476 vol
= module
[instrument
+ index
];
479 if ((vol
& 0xf) >= rmt_volume_silent
[volume
]) {
480 player_calls
= player_call
+ 1;
485 volume_slide
-= volume_slide_depth
;
486 if (volume_slide
< 0) {
488 if (--volume
<= volume_min
)
492 return player_calls
/ per_frame
;
495 FILE_FUNC
void parse_rmt_song(ASAP_ModuleInfo PTR module_info
, const byte ARRAY module
,
496 abool ARRAY global_seen
, int song_len
, int pos_shift
, int pos
)
499 int addr_to_offset
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) - 6;
500 int tempo
= UBYTE(module
[0xb]);
502 int song_offset
= UBYTE(module
[0x14]) + (UBYTE(module
[0x15]) << 8) - addr_to_offset
;
503 int pattern_lo_offset
= UBYTE(module
[0x10]) + (UBYTE(module
[0x11]) << 8) - addr_to_offset
;
504 int pattern_hi_offset
= UBYTE(module
[0x12]) + (UBYTE(module
[0x13]) << 8) - addr_to_offset
;
505 int instrument_frames
;
506 NEW_ARRAY(byte
, seen
, 256);
507 NEW_ARRAY(int, pattern_begin
, 8);
508 NEW_ARRAY(int, pattern_offset
, 8);
509 NEW_ARRAY(int, blank_rows
, 8);
510 NEW_ARRAY(int, instrument_no
, 8);
511 NEW_ARRAY(int, instrument_frame
, 8);
512 NEW_ARRAY(int, volume_value
, 8);
513 NEW_ARRAY(int, volume_frame
, 8);
515 INIT_ARRAY(instrument_no
);
516 INIT_ARRAY(instrument_frame
);
517 INIT_ARRAY(volume_value
);
518 INIT_ARRAY(volume_frame
);
519 while (pos
< song_len
) {
522 if (seen
[pos
] != 0) {
523 if (seen
[pos
] != SEEN_THIS_CALL
)
524 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
527 seen
[pos
] = SEEN_THIS_CALL
;
528 global_seen
[pos
] = TRUE
;
529 if (UBYTE(module
[song_offset
+ (pos
<< pos_shift
)]) == 0xfe) {
530 pos
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + 1]);
533 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
534 i
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + ch
]);
536 blank_rows
[ch
] = 256;
538 pattern_offset
[ch
] = pattern_begin
[ch
] = UBYTE(module
[pattern_lo_offset
+ i
])
539 + (UBYTE(module
[pattern_hi_offset
+ i
]) << 8) - addr_to_offset
;
543 for (i
= 0; i
< song_len
; i
++)
544 if (seen
[i
] == SEEN_THIS_CALL
)
545 seen
[i
] = SEEN_BEFORE
;
546 for (pattern_rows
= UBYTE(module
[0xa]); --pattern_rows
>= 0; ) {
547 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
548 if (--blank_rows
[ch
] > 0)
551 i
= UBYTE(module
[pattern_offset
[ch
]++]);
552 if ((i
& 0x3f) < 62) {
553 i
+= UBYTE(module
[pattern_offset
[ch
]++]) << 8;
554 if ((i
& 0x3f) != 61) {
555 instrument_no
[ch
] = i
>> 10;
556 instrument_frame
[ch
] = frames
;
558 volume_value
[ch
] = (i
>> 6) & 0xf;
559 volume_frame
[ch
] = frames
;
563 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
566 if ((i
& 0x3f) == 62) {
567 blank_rows
[ch
] = i
>> 6;
570 if ((i
& 0xbf) == 63) {
571 tempo
= UBYTE(module
[pattern_offset
[ch
]++]);
575 pattern_offset
[ch
] = pattern_begin
[ch
] + UBYTE(module
[pattern_offset
[ch
]]);
578 /* assert(i == 0xff); */
582 if (pattern_rows
< 0)
585 if (pattern_rows
>= 0)
590 instrument_frames
= 0;
591 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
592 int frame
= instrument_frame
[ch
];
593 frame
+= rmt_instrument_frames(module
, instrument_no
[ch
], volume_value
[ch
], volume_frame
[ch
] - frame
, ch
>= 4);
594 if (instrument_frames
< frame
)
595 instrument_frames
= frame
;
597 if (frames
> instrument_frames
) {
598 if (frames
- instrument_frames
> 100)
599 MODULE_INFO loops
[MODULE_INFO songs
] = FALSE
;
600 frames
= instrument_frames
;
603 set_song_duration(module_info
, frames
);
606 FILE_FUNC abool
parse_rmt(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
607 const byte ARRAY module
, int module_len
)
613 NEW_ARRAY(abool
, global_seen
, 256);
614 if (module_len
< 0x30 || module
[6] != 'R' || module
[7] != 'M'
615 || module
[8] != 'T' || module
[0xd] != 1)
617 switch ((char) module
[9]) {
622 MODULE_INFO channels
= 2;
628 per_frame
= module
[0xc];
629 if (per_frame
< 1 || per_frame
> 4)
631 MODULE_INFO type
= 'r';
632 if (!load_native(ast
, module_info
, module
, module_len
,
633 MODULE_INFO channels
== 2 ? GET_OBX(rmt8
) : GET_OBX(rmt4
)))
635 song_len
= UBYTE(module
[4]) + (UBYTE(module
[5]) << 8) + 1
636 - UBYTE(module
[0x14]) - (UBYTE(module
[0x15]) << 8);
637 if (pos_shift
== 3 && (song_len
& 4) != 0
638 && UBYTE(module
[6 + UBYTE(module
[4]) + (UBYTE(module
[5]) << 8)
639 - UBYTE(module
[2]) - (UBYTE(module
[3]) << 8) - 3]) == 0xfe)
641 song_len
>>= pos_shift
;
642 if (song_len
>= 0x100)
644 INIT_ARRAY(global_seen
);
645 MODULE_INFO songs
= 0;
646 for (pos
= 0; pos
< song_len
&& MODULE_INFO songs
< MAX_SONGS
; pos
++) {
647 if (!global_seen
[pos
]) {
648 MODULE_INFO song_pos
[MODULE_INFO songs
] = (byte
) pos
;
649 parse_rmt_song(module_info
, module
, global_seen
, song_len
, pos_shift
, pos
);
652 /* must set fastplay after song durations calculations, so they assume 312 */
653 MODULE_INFO fastplay
= perframe2fastplay
[per_frame
- 1];
654 MODULE_INFO player
= 0x600;
655 return MODULE_INFO songs
!= 0;
658 FILE_FUNC
void parse_tmc_song(ASAP_ModuleInfo PTR module_info
, const byte ARRAY module
, int pos
)
660 int addr_to_offset
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) - 6;
661 int tempo
= UBYTE(module
[0x24]) + 1;
663 NEW_ARRAY(int, pattern_offset
, 8);
664 NEW_ARRAY(int, blank_rows
, 8);
665 while (UBYTE(module
[0x1a6 + 15 + pos
]) < 0x80) {
668 for (ch
= 7; ch
>= 0; ch
--) {
669 int pat
= UBYTE(module
[0x1a6 + 15 + pos
- 2 * ch
]);
670 pattern_offset
[ch
] = UBYTE(module
[0xa6 + pat
]) + (UBYTE(module
[0x126 + pat
]) << 8) - addr_to_offset
;
673 for (pattern_rows
= 64; --pattern_rows
>= 0; ) {
674 for (ch
= 7; ch
>= 0; ch
--) {
675 if (--blank_rows
[ch
] >= 0)
678 int i
= UBYTE(module
[pattern_offset
[ch
]++]);
680 pattern_offset
[ch
]++;
684 i
= UBYTE(module
[pattern_offset
[ch
]++]);
688 tempo
= (i
& 0x7f) + 1;
690 pattern_offset
[ch
]++;
694 i
= module
[pattern_offset
[ch
]++] & 0x7f;
699 pattern_offset
[ch
]++;
704 blank_rows
[ch
] = i
- 0xbf;
712 if (UBYTE(module
[0x1a6 + 14 + pos
]) < 0x80)
713 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
714 set_song_duration(module_info
, frames
);
717 FILE_FUNC abool
parse_tmc(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
718 const byte ARRAY module
, int module_len
)
722 if (module_len
< 0x1d0)
724 MODULE_INFO type
= 't';
725 if (!load_native(ast
, module_info
, module
, module_len
, GET_OBX(tmc
)))
727 MODULE_INFO channels
= 2;
729 /* find first instrument */
730 while (module
[0x66 + i
] == 0) {
732 return FALSE
; /* no instrument */
734 last_pos
= (UBYTE(module
[0x66 + i
]) << 8) + UBYTE(module
[0x26 + i
])
735 - UBYTE(module
[2]) - (UBYTE(module
[3]) << 8) - 0x1b0;
736 if (0x1b5 + last_pos
>= module_len
)
738 /* skip trailing jumps */
741 return FALSE
; /* no pattern to play */
743 } while (UBYTE(module
[0x1b5 + last_pos
]) >= 0x80);
744 MODULE_INFO songs
= 0;
745 parse_tmc_song(module_info
, module
, 0);
746 for (i
= 0; i
< last_pos
&& MODULE_INFO songs
< MAX_SONGS
; i
+= 16)
747 if (UBYTE(module
[0x1b5 + i
]) >= 0x80)
748 parse_tmc_song(module_info
, module
, i
+ 16);
749 /* must set fastplay after song durations calculations, so they assume 312 */
754 AST tmc_per_frame
= module
[0x25];
755 MODULE_INFO fastplay
= perframe2fastplay
[i
- 1];
759 FILE_FUNC
void parse_tm2_song(ASAP_ModuleInfo PTR module_info
, const byte ARRAY module
, int pos
)
761 int addr_to_offset
= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) - 6;
762 int tempo
= UBYTE(module
[0x24]) + 1;
763 int player_calls
= 0;
764 NEW_ARRAY(int, pattern_offset
, 8);
765 NEW_ARRAY(int, blank_rows
, 8);
768 int pattern_rows
= UBYTE(module
[0x386 + 16 + pos
]);
769 if (pattern_rows
== 0)
771 if (pattern_rows
>= 0x80) {
772 MODULE_INFO loops
[MODULE_INFO songs
] = TRUE
;
775 for (ch
= 7; ch
>= 0; ch
--) {
776 int pat
= UBYTE(module
[0x386 + 15 + pos
- 2 * ch
]);
777 pattern_offset
[ch
] = UBYTE(module
[0x106 + pat
]) + (UBYTE(module
[0x206 + pat
]) << 8) - addr_to_offset
;
780 while (--pattern_rows
>= 0) {
781 for (ch
= 7; ch
>= 0; ch
--) {
782 if (--blank_rows
[ch
] >= 0)
785 int i
= UBYTE(module
[pattern_offset
[ch
]++]);
787 pattern_offset
[ch
]++;
791 if (UBYTE(module
[pattern_offset
[ch
]++]) >= 0x80)
792 pattern_offset
[ch
]++;
796 pattern_offset
[ch
]++;
800 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
810 pattern_offset
[ch
]++;
814 pattern_offset
[ch
] += 2;
818 blank_rows
[ch
] = i
- 0xf0;
825 player_calls
+= tempo
;
829 set_song_duration(module_info
, player_calls
);
832 FILE_FUNC abool
parse_tm2(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
833 const byte ARRAY module
, int module_len
)
838 if (module_len
< 0x3a4)
840 MODULE_INFO type
= 'T';
841 if (!load_native(ast
, module_info
, module
, module_len
, GET_OBX(tm2
)))
846 MODULE_INFO fastplay
= perframe2fastplay
[i
- 1];
847 MODULE_INFO player
= 0x500;
848 if (module
[0x1f] != 0)
849 MODULE_INFO channels
= 2;
851 for (i
= 0; i
< 0x80; i
++) {
852 int instr_addr
= UBYTE(module
[0x86 + i
]) + (UBYTE(module
[0x306 + i
]) << 8);
853 if (instr_addr
!= 0 && instr_addr
< last_pos
)
854 last_pos
= instr_addr
;
856 for (i
= 0; i
< 0x100; i
++) {
857 int pattern_addr
= UBYTE(module
[0x106 + i
]) + (UBYTE(module
[0x206 + i
]) << 8);
858 if (pattern_addr
!= 0 && pattern_addr
< last_pos
)
859 last_pos
= pattern_addr
;
861 last_pos
-= UBYTE(module
[2]) + (UBYTE(module
[3]) << 8) + 0x380;
862 if (0x386 + last_pos
>= module_len
)
864 /* skip trailing stop/jump commands */
869 c
= UBYTE(module
[0x386 + 16 + last_pos
]);
870 } while (c
== 0 || c
>= 0x80);
871 MODULE_INFO songs
= 0;
872 parse_tm2_song(module_info
, module
, 0);
873 for (i
= 0; i
< last_pos
&& MODULE_INFO songs
< MAX_SONGS
; i
+= 17) {
874 c
= UBYTE(module
[0x386 + 16 + i
]);
875 if (c
== 0 || c
>= 0x80)
876 parse_tm2_song(module_info
, module
, i
+ 17);
881 #if !defined(JAVA) && !defined(CSHARP)
883 static abool
parse_hex(int *retval
, const char *p
)
891 if (c
>= '0' && c
<= '9')
893 else if (c
>= 'A' && c
<= 'F')
895 else if (c
>= 'a' && c
<= 'f')
899 } while (*++p
!= '\0');
904 static abool
parse_dec(int *retval
, const char *p
, int minval
, int maxval
)
909 if (c
>= '0' && c
<= '9')
910 r
= 10 * r
+ c
- '0';
915 } while (*++p
!= '\0');
922 static abool
parse_text(char *retval
, const char *p
)
928 if (p
[0] == '<' && p
[1] == '?' && p
[2] == '>' && p
[3] == '"')
942 int ASAP_ParseDuration(const char *s
)
945 if (*s
< '0' || *s
> '9')
948 if (*s
>= '0' && *s
<= '9')
949 r
= 10 * r
+ *s
++ - '0';
952 if (*s
< '0' || *s
> '5')
954 r
= 60 * r
+ (*s
++ - '0') * 10;
955 if (*s
< '0' || *s
> '9')
963 if (*s
< '0' || *s
> '9')
965 r
+= 100 * (*s
++ - '0');
966 if (*s
< '0' || *s
> '9')
968 r
+= 10 * (*s
++ - '0');
969 if (*s
< '0' || *s
> '9')
975 static char *two_digits(char *s
, int x
)
982 void ASAP_DurationToString(char *s
, int duration
)
985 int seconds
= duration
/ 1000;
986 int minutes
= seconds
/ 60;
987 s
= two_digits(s
, minutes
);
989 s
= two_digits(s
, seconds
% 60);
993 s
= two_digits(s
, duration
/ 10);
996 *s
++ = '0' + duration
;
1002 #endif /* !defined(JAVA) && !defined(CSHARP) */
1004 FILE_FUNC abool
parse_sap_header(ASAP_ModuleInfo PTR module_info
,
1005 const byte ARRAY module
, int module_len
)
1007 int module_index
= 0;
1008 abool sap_signature
= FALSE
;
1009 int duration_index
= 0;
1011 NEW_ARRAY(char, line
, 256);
1013 #if !defined(JAVA) && !defined(CSHARP)
1016 if (module_index
+ 8 >= module_len
)
1018 if (UBYTE(module
[module_index
]) == 0xff)
1021 while (module
[module_index
] != 0x0d) {
1022 line
[i
++] = (char) module
[module_index
++];
1023 if (module_index
>= module_len
|| (unsigned)i
>= sizeof(line
) - 1)
1026 if (++module_index
>= module_len
|| module
[module_index
++] != 0x0a)
1030 String tag
= new String(line
, 0, i
);
1032 i
= tag
.indexOf(' ');
1034 arg
= tag
.substring(i
+ 1);
1035 tag
= tag
.substring(0, i
);
1037 #define TAG_IS(t) tag.equals(t)
1038 #define CHAR_ARG arg.charAt(0)
1039 #define SET_HEX(v) v = Integer.parseInt(arg, 16)
1040 #define SET_DEC(v, min, max) do { v = Integer.parseInt(arg); if (v < min || v > max) return FALSE; } while (FALSE)
1041 #define SET_TEXT(v) v = arg.substring(1, arg.length() - 1)
1042 #define DURATION_ARG parseDuration(arg)
1043 #define ARG_CONTAINS(t) (arg.indexOf(t) >= 0)
1044 #elif defined(CSHARP)
1045 string tag
= new string(line
, 0, i
);
1047 i
= tag
.IndexOf(' ');
1049 arg
= tag
.Substring(i
+ 1);
1050 tag
= tag
.Substring(0, i
);
1052 #define TAG_IS(t) tag == t
1053 #define CHAR_ARG arg[0]
1054 #define SET_HEX(v) v = int.Parse(arg, System.Globalization.NumberStyles.HexNumber)
1055 #define SET_DEC(v, min, max) do { v = int.Parse(arg); if (v < min || v > max) return FALSE; } while (FALSE)
1056 #define SET_TEXT(v) v = arg.Substring(1, arg.Length - 1)
1057 #define DURATION_ARG ParseDuration(arg)
1058 #define ARG_CONTAINS(t) (arg.IndexOf(t) >= 0)
1061 for (p
= line
; *p
!= '\0'; p
++) {
1067 #define TAG_IS(t) (strcmp(line, t) == 0)
1069 #define SET_HEX(v) do { if (!parse_hex(&v, p)) return FALSE; } while (FALSE)
1070 #define SET_DEC(v, min, max) do { if (!parse_dec(&v, p, min, max)) return FALSE; } while (FALSE)
1071 #define SET_TEXT(v) do { if (!parse_text(v, p)) return FALSE; } while (FALSE)
1072 #define DURATION_ARG ASAP_ParseDuration(p)
1073 #define ARG_CONTAINS(t) (strstr(p, t) != NULL)
1077 sap_signature
= TRUE
;
1080 if (TAG_IS("AUTHOR"))
1081 SET_TEXT(MODULE_INFO author
);
1082 else if (TAG_IS("NAME"))
1083 SET_TEXT(MODULE_INFO name
);
1084 else if (TAG_IS("DATE"))
1085 SET_TEXT(MODULE_INFO date
);
1086 else if (TAG_IS("SONGS"))
1087 SET_DEC(MODULE_INFO songs
, 1, MAX_SONGS
);
1088 else if (TAG_IS("DEFSONG"))
1089 SET_DEC(MODULE_INFO default_song
, 0, MAX_SONGS
- 1);
1090 else if (TAG_IS("STEREO"))
1091 MODULE_INFO channels
= 2;
1092 else if (TAG_IS("TIME")) {
1093 int duration
= DURATION_ARG
;
1094 if (duration
< 0 || duration_index
>= MAX_SONGS
)
1096 MODULE_INFO durations
[duration_index
] = duration
;
1097 if (ARG_CONTAINS("LOOP"))
1098 MODULE_INFO loops
[duration_index
] = TRUE
;
1101 else if (TAG_IS("TYPE"))
1102 MODULE_INFO type
= CHAR_ARG
;
1103 else if (TAG_IS("FASTPLAY"))
1104 SET_DEC(MODULE_INFO fastplay
, 1, 312);
1105 else if (TAG_IS("MUSIC"))
1106 SET_HEX(MODULE_INFO music
);
1107 else if (TAG_IS("INIT"))
1108 SET_HEX(MODULE_INFO init
);
1109 else if (TAG_IS("PLAYER"))
1110 SET_HEX(MODULE_INFO player
);
1112 if (MODULE_INFO default_song
>= MODULE_INFO songs
)
1114 switch (MODULE_INFO type
) {
1117 if (MODULE_INFO player
< 0 || MODULE_INFO init
< 0)
1121 if (MODULE_INFO player
< 0 || MODULE_INFO music
< 0)
1125 if (MODULE_INFO init
< 0)
1127 MODULE_INFO fastplay
= 78;
1132 if (UBYTE(module
[module_index
+ 1]) != 0xff)
1134 MODULE_INFO header_len
= module_index
;
1138 FILE_FUNC abool
parse_sap(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
1139 const byte ARRAY module
, int module_len
)
1142 if (!parse_sap_header(module_info
, module
, module_len
))
1146 ZERO_ARRAY(AST memory
);
1147 module_index
= MODULE_INFO header_len
+ 2;
1148 while (module_index
+ 5 <= module_len
) {
1149 int start_addr
= UBYTE(module
[module_index
]) + (UBYTE(module
[module_index
+ 1]) << 8);
1150 int block_len
= UBYTE(module
[module_index
+ 2]) + (UBYTE(module
[module_index
+ 3]) << 8) + 1 - start_addr
;
1151 if (block_len
<= 0 || module_index
+ block_len
> module_len
)
1154 COPY_ARRAY(AST memory
, start_addr
, module
, module_index
, block_len
);
1155 module_index
+= block_len
;
1156 if (module_index
== module_len
)
1158 if (module_index
+ 7 <= module_len
1159 && UBYTE(module
[module_index
]) == 0xff && UBYTE(module
[module_index
+ 1]) == 0xff)
1165 #define ASAP_EXT(c1, c2, c3) (((c1) + ((c2) << 8) + ((c3) << 16)) | 0x202020)
1167 FILE_FUNC
int get_packed_ext(STRING filename
)
1170 int i
= filename
.length();
1173 if (filename
.charAt(i
) == '.')
1174 return ext
| 0x202020;
1175 ext
= (ext
<< 8) + filename
.charAt(i
);
1178 #elif defined(CSHARP)
1179 int i
= filename
.Length
;
1182 if (filename
[i
] == '.')
1183 return ext
| 0x202020;
1184 ext
= (ext
<< 8) + filename
[i
];
1190 for (p
= filename
; *p
!= '\0'; p
++);
1193 if (--p
<= filename
|| *p
<= ' ')
1194 return 0; /* no filename extension or invalid character */
1196 return ext
| 0x202020;
1197 ext
= (ext
<< 8) + (*p
& 0xff);
1202 FILE_FUNC abool
is_our_ext(int ext
)
1205 case ASAP_EXT('C', 'M', 'C'):
1206 case ASAP_EXT('C', 'M', 'R'):
1207 case ASAP_EXT('D', 'M', 'C'):
1208 case ASAP_EXT('M', 'P', 'D'):
1209 case ASAP_EXT('M', 'P', 'T'):
1210 case ASAP_EXT('R', 'M', 'T'):
1211 case ASAP_EXT('S', 'A', 'P'):
1212 case ASAP_EXT('T', 'M', '2'):
1213 case ASAP_EXT('T', 'M', '8'):
1214 case ASAP_EXT('T', 'M', 'C'):
1221 ASAP_FUNC abool
ASAP_IsOurFile(STRING filename
)
1223 int ext
= get_packed_ext(filename
);
1224 return is_our_ext(ext
);
1227 ASAP_FUNC abool
ASAP_IsOurExt(STRING ext
)
1230 return ext
.length() == 3
1231 && is_our_ext(ASAP_EXT(ext
.charAt(0), ext
.charAt(1), ext
.charAt(2)));
1233 return ext
[0] > ' ' && ext
[1] > ' ' && ext
[2] > ' ' && ext
[3] == '\0'
1234 && is_our_ext(ASAP_EXT(ext
[0], ext
[1], ext
[2]));
1238 FILE_FUNC abool
parse_file(ASAP_State PTR ast
, ASAP_ModuleInfo PTR module_info
,
1239 STRING filename
, const byte ARRAY module
, int module_len
)
1245 for (i
= 0; i
< filename
.length(); i
++) {
1246 int c
= filename
.charAt(i
);
1247 if (c
== '/' || c
== '\\')
1254 module_info
.author
= "";
1255 module_info
.name
= filename
.substring(basename
, ext
);
1256 module_info
.date
= "";
1257 #elif defined(CSHARP)
1260 for (i
= 0; i
< filename
.Length
; i
++) {
1261 int c
= filename
[i
];
1262 if (c
== '/' || c
== '\\')
1269 module_info
.author
= string
.Empty
;
1270 module_info
.name
= filename
.Substring(basename
, ext
- basename
);
1271 module_info
.date
= string
.Empty
;
1274 const char *basename
= filename
;
1275 const char *ext
= NULL
;
1276 for (p
= filename
; *p
!= '\0'; p
++) {
1277 if (*p
== '/' || *p
== '\\')
1284 module_info
->author
[0] = '\0';
1286 memcpy(module_info
->name
, basename
, i
);
1287 module_info
->name
[i
] = '\0';
1288 module_info
->date
[0] = '\0';
1290 MODULE_INFO channels
= 1;
1291 MODULE_INFO songs
= 1;
1292 MODULE_INFO default_song
= 0;
1293 for (i
= 0; i
< MAX_SONGS
; i
++) {
1294 MODULE_INFO durations
[i
] = -1;
1295 MODULE_INFO loops
[i
] = FALSE
;
1297 MODULE_INFO type
= '?';
1298 MODULE_INFO fastplay
= 312;
1299 MODULE_INFO music
= -1;
1300 MODULE_INFO init
= -1;
1301 MODULE_INFO player
= -1;
1302 switch (get_packed_ext(filename
)) {
1303 case ASAP_EXT('C', 'M', 'C'):
1304 return parse_cmc(ast
, module_info
, module
, module_len
, FALSE
);
1305 case ASAP_EXT('C', 'M', 'R'):
1306 return parse_cmc(ast
, module_info
, module
, module_len
, TRUE
);
1307 case ASAP_EXT('D', 'M', 'C'):
1308 MODULE_INFO fastplay
= 156;
1309 return parse_cmc(ast
, module_info
, module
, module_len
, FALSE
);
1310 case ASAP_EXT('M', 'P', 'D'):
1311 MODULE_INFO fastplay
= 156;
1312 return parse_mpt(ast
, module_info
, module
, module_len
);
1313 case ASAP_EXT('M', 'P', 'T'):
1314 return parse_mpt(ast
, module_info
, module
, module_len
);
1315 case ASAP_EXT('R', 'M', 'T'):
1316 return parse_rmt(ast
, module_info
, module
, module_len
);
1317 case ASAP_EXT('S', 'A', 'P'):
1318 return parse_sap(ast
, module_info
, module
, module_len
);
1319 case ASAP_EXT('T', 'M', '2'):
1320 return parse_tm2(ast
, module_info
, module
, module_len
);
1321 case ASAP_EXT('T', 'M', '8'):
1322 case ASAP_EXT('T', 'M', 'C'):
1323 return parse_tmc(ast
, module_info
, module
, module_len
);
1329 ASAP_FUNC abool
ASAP_GetModuleInfo(ASAP_ModuleInfo PTR module_info
, STRING filename
,
1330 const byte ARRAY module
, int module_len
)
1332 return parse_file(NULL
, module_info
, filename
, module
, module_len
);
1335 ASAP_FUNC abool
ASAP_Load(ASAP_State PTR ast
, STRING filename
,
1336 const byte ARRAY module
, int module_len
)
1338 AST silence_cycles
= 0;
1339 return parse_file(ast
, ADDRESSOF AST module_info
, filename
, module
, module_len
);
1342 ASAP_FUNC
void ASAP_DetectSilence(ASAP_State PTR ast
, int seconds
)
1344 AST silence_cycles
= seconds
* ASAP_MAIN_CLOCK
;
1347 FILE_FUNC
void call_6502(ASAP_State PTR ast
, int addr
, int max_scanlines
)
1350 /* put a CIM at 0xd20a and a return address on stack */
1351 dPutByte(0xd20a, 0xd2);
1352 dPutByte(0x01fe, 0x09);
1353 dPutByte(0x01ff, 0xd2);
1355 Cpu_RunScanlines(ast
, max_scanlines
);
1358 /* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */
1359 #define SCANLINES_FOR_INIT (50 * 312)
1361 FILE_FUNC
void call_6502_init(ASAP_State PTR ast
, int addr
, int a
, int x
, int y
)
1363 AST cpu_a
= a
& 0xff;
1364 AST cpu_x
= x
& 0xff;
1365 AST cpu_y
= y
& 0xff;
1366 call_6502(ast
, addr
, SCANLINES_FOR_INIT
);
1369 ASAP_FUNC
void ASAP_PlaySong(ASAP_State PTR ast
, int song
, int duration
)
1371 AST current_song
= song
;
1372 AST current_duration
= duration
;
1373 AST blocks_played
= 0;
1374 AST silence_cycles_counter
= AST silence_cycles
;
1375 AST extra_pokey_mask
= AST module_info
.channels
> 1 ? 0x10 : 0;
1376 PokeySound_Initialize(ast
);
1381 AST scanline_number
= 0;
1382 AST next_scanline_cycle
= 0;
1383 AST timer1_cycle
= NEVER
;
1384 AST timer2_cycle
= NEVER
;
1385 AST timer4_cycle
= NEVER
;
1387 switch (AST module_info
.type
) {
1389 call_6502_init(ast
, AST module_info
.init
, song
, 0, 0);
1394 call_6502_init(ast
, AST module_info
.player
+ 3, 0x70, AST module_info
.music
, AST module_info
.music
>> 8);
1395 call_6502_init(ast
, AST module_info
.player
+ 3, 0x00, song
, 0);
1403 AST cpu_pc
= AST module_info
.init
;
1406 call_6502_init(ast
, AST module_info
.player
, 0x00, AST module_info
.music
>> 8, AST module_info
.music
);
1407 call_6502_init(ast
, AST module_info
.player
, 0x02, AST module_info
.song_pos
[song
], 0);
1410 call_6502_init(ast
, AST module_info
.player
, AST module_info
.song_pos
[song
], AST module_info
.music
, AST module_info
.music
>> 8);
1414 call_6502_init(ast
, AST module_info
.player
, 0x70, AST module_info
.music
>> 8, AST module_info
.music
);
1415 call_6502_init(ast
, AST module_info
.player
, 0x00, song
, 0);
1416 AST tmc_per_frame_counter
= 1;
1419 ASAP_MutePokeyChannels(ast
, 0);
1422 ASAP_FUNC
void ASAP_MutePokeyChannels(ASAP_State PTR ast
, int mask
)
1424 PokeySound_Mute(ast
, ADDRESSOF AST base_pokey
, mask
);
1425 PokeySound_Mute(ast
, ADDRESSOF AST extra_pokey
, mask
>> 4);
1428 ASAP_FUNC abool
call_6502_player(ASAP_State PTR ast
)
1431 PokeySound_StartFrame(ast
);
1432 switch (AST module_info
.type
) {
1434 call_6502(ast
, AST module_info
.player
, AST module_info
.fastplay
);
1439 call_6502(ast
, AST module_info
.player
+ 6, AST module_info
.fastplay
);
1443 #define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff
1444 #define RETURN_FROM_PLAYER_ADDR 0xd200
1445 /* save 6502 state on 6502 stack */
1446 PUSH_ON_6502_STACK(AST cpu_pc
>> 8);
1447 PUSH_ON_6502_STACK(AST cpu_pc
& 0xff);
1448 PUSH_ON_6502_STACK(((AST cpu_nz
| (AST cpu_nz
>> 1)) & 0x80) + AST cpu_vdi
+ \
1449 ((AST cpu_nz
& 0xff) == 0 ? Z_FLAG
: 0) + AST cpu_c
+ 0x20);
1450 PUSH_ON_6502_STACK(AST cpu_a
);
1451 PUSH_ON_6502_STACK(AST cpu_x
);
1452 PUSH_ON_6502_STACK(AST cpu_y
);
1453 /* RTS will jump to 6502 code that restores the state */
1454 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) >> 8);
1455 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) & 0xff);
1457 dPutByte(RETURN_FROM_PLAYER_ADDR
, 0x68); /* PLA */
1458 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 1, 0xa8); /* TAY */
1459 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 2, 0x68); /* PLA */
1460 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 3, 0xaa); /* TAX */
1461 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 4, 0x68); /* PLA */
1462 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 5, 0x40); /* RTI */
1463 AST cpu_pc
= AST module_info
.player
;
1464 Cpu_RunScanlines(ast
, AST module_info
.fastplay
);
1467 Cpu_RunScanlines(ast
, AST module_info
.fastplay
);
1469 int i
= dGetByte(0x45) - 1;
1472 dPutByte(0xb07b, dGetByte(0xb07b) + 1);
1478 call_6502(ast
, AST module_info
.player
+ 3, AST module_info
.fastplay
);
1481 if (--AST tmc_per_frame_counter
<= 0) {
1482 AST tmc_per_frame_counter
= AST tmc_per_frame
;
1483 call_6502(ast
, AST module_info
.player
+ 3, AST module_info
.fastplay
);
1486 call_6502(ast
, AST module_info
.player
+ 6, AST module_info
.fastplay
);
1489 PokeySound_EndFrame(ast
, AST module_info
.fastplay
* 114);
1490 if (AST silence_cycles
> 0) {
1491 if (PokeySound_IsSilent(ADDRESSOF AST base_pokey
)
1492 && PokeySound_IsSilent(ADDRESSOF AST extra_pokey
)) {
1493 AST silence_cycles_counter
-= AST module_info
.fastplay
* 114;
1494 if (AST silence_cycles_counter
<= 0)
1498 AST silence_cycles_counter
= AST silence_cycles
;
1503 FILE_FUNC
int milliseconds_to_blocks(int milliseconds
)
1505 return milliseconds
* (ASAP_SAMPLE_RATE
/ 100) / 10;
1508 ASAP_FUNC
void ASAP_Seek(ASAP_State PTR ast
, int position
)
1510 int block
= milliseconds_to_blocks(position
);
1511 if (block
< AST blocks_played
)
1512 ASAP_PlaySong(ast
, AST current_song
, AST current_duration
);
1513 while (AST blocks_played
+ AST samples
- AST sample_index
< block
) {
1514 AST blocks_played
+= AST samples
- AST sample_index
;
1515 call_6502_player(ast
);
1517 AST sample_index
+= block
- AST blocks_played
;
1518 AST blocks_played
= block
;
1521 ASAP_FUNC
int ASAP_Generate(ASAP_State PTR ast
, VOIDPTR buffer
, int buffer_len
,
1522 ASAP_SampleFormat format
)
1527 if (AST silence_cycles
> 0 && AST silence_cycles_counter
<= 0)
1529 block_shift
= (AST module_info
.channels
- 1) + (format
!= ASAP_FORMAT_U8
? 1 : 0);
1530 buffer_blocks
= buffer_len
>> block_shift
;
1531 if (AST current_duration
> 0) {
1532 int total_blocks
= milliseconds_to_blocks(AST current_duration
);
1533 if (buffer_blocks
> total_blocks
- AST blocks_played
)
1534 buffer_blocks
= total_blocks
- AST blocks_played
;
1538 int blocks
= PokeySound_Generate(ast
, buffer
, block
<< block_shift
, buffer_blocks
- block
, format
);
1539 AST blocks_played
+= blocks
;
1541 } while (block
< buffer_blocks
&& call_6502_player(ast
));
1542 return block
<< block_shift
;
1545 #if !defined(JAVA) && !defined(CSHARP)
1547 abool
ASAP_ChangeExt(char *filename
, const char *ext
)
1550 while (*filename
!= '\0') {
1551 if (*filename
== '/' || *filename
== '\\')
1553 else if (*filename
== '.')
1554 dest
= filename
+ 1;
1563 abool
ASAP_CanSetModuleInfo(const char *filename
)
1565 int ext
= get_packed_ext(filename
);
1566 return ext
== ASAP_EXT('S', 'A', 'P');
1569 static byte
*put_string(byte
*dest
, const char *str
)
1571 while (*str
!= '\0')
1576 static byte
*put_dec(byte
*dest
, int value
)
1579 dest
= put_dec(dest
, value
/ 10);
1582 *dest
++ = '0' + value
;
1586 static byte
*put_text_tag(byte
*dest
, const char *tag
, const char *value
)
1588 dest
= put_string(dest
, tag
);
1593 while (*value
!= '\0') {
1594 if (*value
< ' ' || *value
> 'z' || *value
== '"' || *value
== '`')
1604 static byte
*put_hex_tag(byte
*dest
, const char *tag
, int value
)
1609 dest
= put_string(dest
, tag
);
1611 for (i
= 12; i
>= 0; i
-= 4) {
1612 int digit
= (value
>> i
) & 0xf;
1613 *dest
++ = (byte
) (digit
+ (digit
< 10 ? '0' : 'A' - 10));
1620 static byte
*put_dec_tag(byte
*dest
, const char *tag
, int value
)
1622 dest
= put_string(dest
, tag
);
1624 dest
= put_dec(dest
, value
);
1630 static byte
*start_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1632 dest
= put_string(dest
, "SAP\r\n");
1633 dest
= put_text_tag(dest
, "AUTHOR", module_info
->author
);
1636 dest
= put_text_tag(dest
, "NAME", module_info
->name
);
1639 dest
= put_text_tag(dest
, "DATE", module_info
->date
);
1642 if (module_info
->songs
> 1) {
1643 dest
= put_dec_tag(dest
, "SONGS", module_info
->songs
);
1644 if (module_info
->default_song
> 0)
1645 dest
= put_dec_tag(dest
, "DEFSONG", module_info
->default_song
);
1647 if (module_info
->channels
> 1)
1648 dest
= put_string(dest
, "STEREO\r\n");
1652 static byte
*put_durations(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1655 for (song
= 0; song
< module_info
->songs
; song
++) {
1656 if (module_info
->durations
[song
] < 0)
1658 dest
= put_string(dest
, "TIME ");
1659 ASAP_DurationToString((char *) dest
, module_info
->durations
[song
]);
1660 while (*dest
!= '\0')
1662 if (module_info
->loops
[song
])
1663 dest
= put_string(dest
, " LOOP");
1670 static byte
*put_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
, char type
, int music
, int init
, int player
)
1672 dest
= start_sap_header(dest
, module_info
);
1675 dest
= put_string(dest
, "TYPE ");
1679 if (module_info
->fastplay
!= 312)
1680 dest
= put_dec_tag(dest
, "FASTPLAY", module_info
->fastplay
);
1681 dest
= put_hex_tag(dest
, "MUSIC", music
);
1682 dest
= put_hex_tag(dest
, "INIT", init
);
1683 dest
= put_hex_tag(dest
, "PLAYER", player
);
1684 dest
= put_durations(dest
, module_info
);
1688 int ASAP_SetModuleInfo(const ASAP_ModuleInfo
*module_info
, const byte ARRAY module
,
1689 int module_len
, byte ARRAY out_module
)
1693 if (memcmp(module
, "SAP\r\n", 5) != 0)
1695 dest
= start_sap_header(out_module
, module_info
);
1699 while (i
< module_len
&& module
[i
] != 0xff) {
1700 if (memcmp(module
+ i
, "AUTHOR ", 7) == 0
1701 || memcmp(module
+ i
, "NAME ", 5) == 0
1702 || memcmp(module
+ i
, "DATE ", 5) == 0
1703 || memcmp(module
+ i
, "SONGS ", 6) == 0
1704 || memcmp(module
+ i
, "DEFSONG ", 8) == 0
1705 || memcmp(module
+ i
, "STEREO", 6) == 0
1706 || memcmp(module
+ i
, "TIME ", 5) == 0) {
1707 while (i
< module_len
&& module
[i
++] != 0x0a);
1714 } while (i
< module_len
&& b
!= 0x0a);
1717 dest
= put_durations(dest
, module_info
);
1719 memcpy(dest
, module
+ i
, module_len
);
1721 return dest
- out_module
;
1724 #define RMT_INIT 0x0c80
1725 #define TM2_INIT 0x1080
1727 const char *ASAP_CanConvert(const char *filename
, const ASAP_ModuleInfo
*module_info
,
1728 const byte ARRAY module
, int module_len
)
1731 switch (module_info
->type
) {
1733 if (module_info
->init
== 0x4f3 || module_info
->init
== 0xf4f3 || module_info
->init
== 0x4ef)
1734 return module_info
->fastplay
== 156 ? "mpd" : "mpt";
1735 if (module_info
->init
== RMT_INIT
)
1737 if ((module_info
->init
== 0x4f5 || module_info
->init
== 0xf4f5 || module_info
->init
== 0x4f2)
1738 || ((module_info
->init
== 0x4e7 || module_info
->init
== 0xf4e7 || module_info
->init
== 0x4e4) && module_info
->fastplay
== 156)
1739 || ((module_info
->init
== 0x4e5 || module_info
->init
== 0xf4e5 || module_info
->init
== 0x4e2) && (module_info
->fastplay
== 104 || module_info
->fastplay
== 78)))
1741 if (module_info
->init
== TM2_INIT
)
1745 if (module_info
->player
== 0x500 || module_info
->player
== 0xf500) {
1746 if (module_info
->fastplay
== 156)
1748 return module
[module_len
- 170] == 0x1e ? "cmr" : "cmc";
1764 int ASAP_Convert(const char *filename
, const ASAP_ModuleInfo
*module_info
,
1765 const byte ARRAY module
, int module_len
, byte ARRAY out_module
)
1772 static const int tmc_player
[4] = { 3, -9, -10, -10 };
1773 static const int tmc_init
[4] = { -14, -16, -17, -17 };
1774 switch (module_info
->type
) {
1777 out_len
= module
[module_info
->header_len
+ 4] + (module
[module_info
->header_len
+ 5] << 8)
1778 - module
[module_info
->header_len
+ 2] - (module
[module_info
->header_len
+ 3] << 8) + 7;
1779 if (out_len
< 7 || module_info
->header_len
+ out_len
>= module_len
)
1781 memcpy(out_module
, module
+ module_info
->header_len
, out_len
);
1785 dest
= put_sap_header(out_module
, module_info
, 'C', module_info
->music
, -1, module_info
->player
);
1788 memcpy(dest
, module
, module_len
);
1790 memcpy(dest
, cmc_obx
+ 2, sizeof(cmc_obx
) - 2);
1791 if (module_info
->type
== 'z')
1792 memcpy(dest
+ 4 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, sizeof(cmr_bass_table
));
1793 dest
+= sizeof(cmc_obx
) - 2;
1794 return dest
- out_module
;
1796 if (module_info
->songs
!= 1) {
1797 addr
= module_info
->player
- 17 - module_info
->songs
;
1798 dest
= put_sap_header(out_module
, module_info
, 'B', -1, module_info
->player
- 17, module_info
->player
+ 3);
1801 addr
= module_info
->player
- 13;
1802 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, module_info
->player
+ 3);
1806 memcpy(dest
, module
, module_len
);
1808 *dest
++ = (byte
) addr
;
1809 *dest
++ = (byte
) (addr
>> 8);
1810 *dest
++ = mpt_obx
[4];
1811 *dest
++ = mpt_obx
[5];
1812 if (module_info
->songs
!= 1) {
1813 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
1814 dest
+= module_info
->songs
;
1815 *dest
++ = 0x48; /* pha */
1817 *dest
++ = 0xa0; /* ldy #<music */
1818 *dest
++ = (byte
) module_info
->music
;
1819 *dest
++ = 0xa2; /* ldx #>music */
1820 *dest
++ = (byte
) (module_info
->music
>> 8);
1821 *dest
++ = 0xa9; /* lda #0 */
1823 *dest
++ = 0x20; /* jsr player */
1824 *dest
++ = (byte
) module_info
->player
;
1825 *dest
++ = (byte
) (module_info
->player
>> 8);
1826 if (module_info
->songs
!= 1) {
1827 *dest
++ = 0x68; /* pla */
1828 *dest
++ = 0xa8; /* tay */
1829 *dest
++ = 0xbe; /* ldx song2pos,y */
1830 *dest
++ = (byte
) addr
;
1831 *dest
++ = (byte
) (addr
>> 8);
1834 *dest
++ = 0xa2; /* ldx #0 */
1837 *dest
++ = 0xa9; /* lda #2 */
1839 memcpy(dest
, mpt_obx
+ 6, sizeof(mpt_obx
) - 6);
1840 dest
+= sizeof(mpt_obx
) - 6;
1841 return dest
- out_module
;
1843 dest
= put_sap_header(out_module
, module_info
, 'B', -1, RMT_INIT
, module_info
->player
+ 3);
1846 memcpy(dest
, module
, module_len
);
1848 *dest
++ = (byte
) RMT_INIT
;
1849 *dest
++ = (byte
) (RMT_INIT
>> 8);
1850 if (module_info
->songs
!= 1) {
1851 addr
= RMT_INIT
+ 10 + module_info
->songs
;
1852 *dest
++ = (byte
) addr
;
1853 *dest
++ = (byte
) (addr
>> 8);
1854 *dest
++ = 0xa8; /* tay */
1855 *dest
++ = 0xb9; /* lda song2pos,y */
1856 *dest
++ = (byte
) (RMT_INIT
+ 11);
1857 *dest
++ = (byte
) ((RMT_INIT
+ 11) >> 8);
1860 *dest
++ = (byte
) (RMT_INIT
+ 8);
1861 *dest
++ = (byte
) ((RMT_INIT
+ 8) >> 8);
1862 *dest
++ = 0xa9; /* lda #0 */
1865 *dest
++ = 0xa2; /* ldx #<music */
1866 *dest
++ = (byte
) module_info
->music
;
1867 *dest
++ = 0xa0; /* ldy #>music */
1868 *dest
++ = (byte
) (module_info
->music
>> 8);
1869 *dest
++ = 0x4c; /* jmp player */
1870 *dest
++ = (byte
) module_info
->player
;
1871 *dest
++ = (byte
) (module_info
->player
>> 8);
1872 if (module_info
->songs
!= 1) {
1873 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
1874 dest
+= module_info
->songs
;
1876 if (module_info
->channels
== 1) {
1877 memcpy(dest
, rmt4_obx
+ 2, sizeof(rmt4_obx
) - 2);
1878 dest
+= sizeof(rmt4_obx
) - 2;
1881 memcpy(dest
, rmt8_obx
+ 2, sizeof(rmt8_obx
) - 2);
1882 dest
+= sizeof(rmt8_obx
) - 2;
1884 return dest
- out_module
;
1886 player
= module_info
->player
+ tmc_player
[module
[0x25] - 1];
1887 addr
= player
+ tmc_init
[module
[0x25] - 1];
1888 if (module_info
->songs
!= 1)
1890 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, player
);
1893 memcpy(dest
, module
, module_len
);
1895 *dest
++ = (byte
) addr
;
1896 *dest
++ = (byte
) (addr
>> 8);
1897 *dest
++ = tmc_obx
[4];
1898 *dest
++ = tmc_obx
[5];
1899 if (module_info
->songs
!= 1)
1900 *dest
++ = 0x48; /* pha */
1901 *dest
++ = 0xa0; /* ldy #<music */
1902 *dest
++ = (byte
) module_info
->music
;
1903 *dest
++ = 0xa2; /* ldx #>music */
1904 *dest
++ = (byte
) (module_info
->music
>> 8);
1905 *dest
++ = 0xa9; /* lda #$70 */
1907 *dest
++ = 0x20; /* jsr player */
1908 *dest
++ = (byte
) module_info
->player
;
1909 *dest
++ = (byte
) (module_info
->player
>> 8);
1910 if (module_info
->songs
!= 1) {
1911 *dest
++ = 0x68; /* pla */
1912 *dest
++ = 0xaa; /* tax */
1913 *dest
++ = 0xa9; /* lda #0 */
1917 *dest
++ = 0xa9; /* lda #$60 */
1920 switch (module
[0x25]) {
1922 *dest
++ = 0x06; /* asl 0 */
1924 *dest
++ = 0x4c; /* jmp player */
1925 *dest
++ = (byte
) module_info
->player
;
1926 *dest
++ = (byte
) (module_info
->player
>> 8);
1927 *dest
++ = 0xa5; /* lda 0 */
1929 *dest
++ = 0xe6; /* inc 0 */
1931 *dest
++ = 0x4a; /* lsr @ */
1932 *dest
++ = 0x90; /* bcc player+3 */
1934 *dest
++ = 0xb0; /* bcs player+6 */
1939 *dest
++ = 0xa0; /* ldy #1 */
1941 *dest
++ = 0x84; /* sty 0 */
1943 *dest
++ = 0xd0; /* bne player */
1945 *dest
++ = 0xc6; /* dec 0 */
1947 *dest
++ = 0xd0; /* bne player+6 */
1949 *dest
++ = 0xa0; /* ldy #3 */
1950 *dest
++ = module
[0x25];
1951 *dest
++ = 0x84; /* sty 0 */
1953 *dest
++ = 0xd0; /* bne player+3 */
1959 memcpy(dest
, tmc_obx
+ 6, sizeof(tmc_obx
) - 6);
1960 dest
+= sizeof(tmc_obx
) - 6;
1961 return dest
- out_module
;
1963 dest
= put_sap_header(out_module
, module_info
, 'B', -1, TM2_INIT
, module_info
->player
+ 3);
1966 memcpy(dest
, module
, module_len
);
1968 *dest
++ = (byte
) TM2_INIT
;
1969 *dest
++ = (byte
) (TM2_INIT
>> 8);
1970 if (module_info
->songs
!= 1) {
1971 *dest
++ = (byte
) (TM2_INIT
+ 16);
1972 *dest
++ = (byte
) ((TM2_INIT
+ 16) >> 8);
1973 *dest
++ = 0x48; /* pha */
1976 *dest
++ = (byte
) (TM2_INIT
+ 14);
1977 *dest
++ = (byte
) ((TM2_INIT
+ 14) >> 8);
1979 *dest
++ = 0xa0; /* ldy #<music */
1980 *dest
++ = (byte
) module_info
->music
;
1981 *dest
++ = 0xa2; /* ldx #>music */
1982 *dest
++ = (byte
) (module_info
->music
>> 8);
1983 *dest
++ = 0xa9; /* lda #$70 */
1985 *dest
++ = 0x20; /* jsr player */
1986 *dest
++ = (byte
) module_info
->player
;
1987 *dest
++ = (byte
) (module_info
->player
>> 8);
1988 if (module_info
->songs
!= 1) {
1989 *dest
++ = 0x68; /* pla */
1990 *dest
++ = 0xaa; /* tax */
1991 *dest
++ = 0xa9; /* lda #0 */
1995 *dest
++ = 0xa9; /* lda #0 */
1997 *dest
++ = 0xaa; /* tax */
1999 *dest
++ = 0x4c; /* jmp player */
2000 *dest
++ = (byte
) module_info
->player
;
2001 *dest
++ = (byte
) (module_info
->player
>> 8);
2002 memcpy(dest
, tm2_obx
+ 2, sizeof(tm2_obx
) - 2);
2003 dest
+= sizeof(tm2_obx
) - 2;
2004 return dest
- out_module
;
2010 #endif /* !defined(JAVA) && !defined(CSHARP) */