4 * Copyright (C) 2005-2010 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 static byte s_memory
[65536];
27 static ASAP_ModuleInfo s_module_info
;
31 #define GET_PLAYER(name) NULL
35 #define GET_PLAYER(name) GET_RESOURCE(name, obx)
37 FUNC(int, ASAP_GetByte
, (P(ASAP_State PTR
, ast
), P(int, addr
)))
39 switch (addr
& 0xff1f) {
41 return ast _ module_info
->ntsc
? 0xf : 1;
44 return PokeySound_GetRandom(ast
, addr
, ast _ cycle
);
48 if (ast _ extra_pokey_mask
!= 0) {
49 /* interrupts in the extra POKEY not emulated at the moment */
55 case 0xd20f: /* just because some SAP files rely on this */
60 return ast _ scanline_number
>> 1;
62 return dGetByte(addr
);
66 FUNC(void, ASAP_PutByte
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, data
)))
68 if ((addr
>> 8) == 0xd2) {
69 if ((addr
& (ast _ extra_pokey_mask
+ 0xf)) == 0xe) {
70 ast _ irqst
|= data
^ 0xff;
71 #define SET_TIMER_IRQ(ch) \
72 if ((data & ast _ irqst & ch) != 0) { \
73 if (ast _ timer##ch##_cycle == NEVER) { \
74 V(int, t) = ast _ base_pokey.tick_cycle##ch; \
75 while (t < ast _ cycle) \
76 t += ast _ base_pokey.period_cycles##ch; \
77 ast _ timer##ch##_cycle = t; \
78 if (ast _ nearest_event_cycle > t) \
79 ast _ nearest_event_cycle = t; \
83 ast _ timer##ch##_cycle = NEVER;
89 PokeySound_PutByte(ast
, addr
, data
);
91 else if ((addr
& 0xff0f) == 0xd40a) {
92 if (ast _ cycle
<= ast _ next_scanline_cycle
- 8)
93 ast _ cycle
= ast _ next_scanline_cycle
- 8;
95 ast _ cycle
= ast _ next_scanline_cycle
+ 106;
97 else if ((addr
& 0xff00) == ast _ module_info
->covox_addr
) {
98 V(PokeyState PTR
, pst
);
100 if (addr
== 0 || addr
== 3)
101 pst
= ADDRESSOF ast _ base_pokey
;
103 pst
= ADDRESSOF ast _ extra_pokey
;
104 pst _ delta_buffer
[CYCLE_TO_SAMPLE(ast _ cycle
)] += (data
- UBYTE(ast _ covox
[addr
])) << DELTA_SHIFT_COVOX
;
105 ast _ covox
[addr
] = CAST(byte
) (data
);
107 else if ((addr
& 0xff1f) == 0xd01f) {
108 V(int, sample
) = CYCLE_TO_SAMPLE(ast _ cycle
);
111 /* NOT data - ast _ consol; reverse to the POKEY sound */
112 delta
= (ast _ consol
- data
) << DELTA_SHIFT_GTIA
;
114 ast _ base_pokey
.delta_buffer
[sample
] += delta
;
115 ast _ extra_pokey
.delta_buffer
[sample
] += delta
;
118 dPutByte(addr
, data
);
121 #endif /* ASAP_ONLY_INFO */
123 #define UWORD(array, index) (UBYTE(array[index]) + (UBYTE(array[(index) + 1]) << 8))
125 #ifndef ASAP_ONLY_SAP
127 #ifndef ASAP_ONLY_INFO
133 #define CMR_BASS_TABLE_OFFSET 0x70f
135 CONST_ARRAY(byte
, cmr_bass_table
)
136 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E,
137 0x38, 0x35, CAST(byte
) (0x88), 0x7F, 0x79, 0x73, 0x6C, 0x67,
138 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F,
139 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28,
140 0x25, 0x24, 0x21, 0x1F, 0x1E
143 #endif /* ASAP_ONLY_INFO */
145 CONST_ARRAY(int, perframe2fastplay
)
146 312, 312 / 2, 312 / 3, 312 / 4
149 /* Loads native module (anything except SAP) and 6502 player routine. */
150 PRIVATE
FUNC(abool
, load_native
, (
151 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
152 P(CONST BYTEARRAY
, module
), P(int, module_len
), P(RESOURCE
, player
)))
154 #ifndef ASAP_ONLY_INFO
155 V(int, player_last_byte
);
157 V(int, music_last_byte
);
159 if ((UBYTE(module
[0]) != 0xff || UBYTE(module
[1]) != 0xff)
160 && (module
[0] != 0 || module
[1] != 0)) /* some CMC and clones start with zeros */
162 module_info _ music
= UWORD(module
, 2);
163 #ifndef ASAP_ONLY_INFO
164 module_info _ player
= UWORD(player
, 2);
165 player_last_byte
= UWORD(player
, 4);
166 if (module_info _ music
<= player_last_byte
)
169 music_last_byte
= UWORD(module
, 4);
170 if (module_info _ music
<= 0xd7ff && music_last_byte
>= 0xd000)
172 block_len
= music_last_byte
+ 1 - module_info _ music
;
173 if (6 + block_len
!= module_len
) {
176 if (module_info _ type
!= ASAP_TYPE_RMT
|| 11 + block_len
> module_len
)
178 /* allow optional info for Raster Music Tracker */
179 info_addr
= UWORD(module
, 6 + block_len
);
180 if (info_addr
!= module_info _ music
+ block_len
)
182 info_len
= UWORD(module
, 8 + block_len
) + 1 - info_addr
;
183 if (10 + block_len
+ info_len
!= module_len
)
186 #ifndef ASAP_ONLY_INFO
188 COPY_ARRAY(ast _ memory
, module_info _ music
, module
, 6, block_len
);
189 COPY_ARRAY(ast _ memory
, module_info _ player
, player
, 6, player_last_byte
+ 1 - module_info _ player
);
195 PRIVATE
FUNC(void, set_song_duration
, (P(ASAP_ModuleInfo PTR
, module_info
), P(int, player_calls
)))
197 module_info _ durations
[module_info _ songs
] = TO_INT(player_calls
* module_info _ fastplay
* 114000.0 / 1773447);
198 module_info _ songs
++;
201 #define SEEN_THIS_CALL 1
202 #define SEEN_BEFORE 2
203 #define SEEN_REPEAT 3
205 PRIVATE
FUNC(void, parse_cmc_song
, (P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
207 V(int, tempo
) = UBYTE(module
[0x19]);
208 V(int, player_calls
) = 0;
209 V(int, rep_start_pos
) = 0;
210 V(int, rep_end_pos
) = 0;
211 V(int, rep_times
) = 0;
212 NEW_ARRAY(byte
, seen
, 0x55);
214 while (pos
>= 0 && pos
< 0x55) {
218 if (pos
== rep_end_pos
&& rep_times
> 0) {
219 for (p1
= 0; p1
< 0x55; p1
++)
220 if (seen
[p1
] == SEEN_THIS_CALL
|| seen
[p1
] == SEEN_REPEAT
)
225 if (seen
[pos
] != 0) {
226 if (seen
[pos
] != SEEN_THIS_CALL
)
227 module_info _ loops
[module_info _ songs
] = TRUE
;
230 seen
[pos
] = SEEN_THIS_CALL
;
231 p1
= UBYTE(module
[0x206 + pos
]);
232 p2
= UBYTE(module
[0x25b + pos
]);
233 p3
= UBYTE(module
[0x2b0 + pos
]);
234 if (p1
== 0xfe || p2
== 0xfe || p3
== 0xfe) {
261 rep_end_pos
= pos
+ p2
;
266 module_info _ loops
[module_info _ songs
] = TRUE
;
269 p2
= rep_times
> 0 ? SEEN_REPEAT
: SEEN_BEFORE
;
270 for (p1
= 0; p1
< 0x55; p1
++)
271 if (seen
[p1
] == SEEN_THIS_CALL
)
272 seen
[p1
] = CAST(byte
) p2
;
273 player_calls
+= tempo
* (module_info _ type
== ASAP_TYPE_CM3
? 48 : 64);
276 set_song_duration(module_info
, player_calls
);
279 PRIVATE
FUNC(abool
, parse_cmc
, (
280 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
281 P(CONST BYTEARRAY
, module
), P(int, module_len
), P(int, type
), P(RESOURCE
, player
)))
285 if (module_len
< 0x306)
287 module_info _ type
= type
;
288 if (!load_native(ast
, module_info
, module
, module_len
, player
))
290 #ifndef ASAP_ONLY_INFO
291 if (ast
!= NULL
&& type
== ASAP_TYPE_CMR
)
292 COPY_ARRAY(ast _ memory
, 0x500 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, 0, sizeof(cmr_bass_table
));
295 while (--last_pos
>= 0) {
296 if (UBYTE(module
[0x206 + last_pos
]) < 0xb0
297 || UBYTE(module
[0x25b + last_pos
]) < 0x40
298 || UBYTE(module
[0x2b0 + last_pos
]) < 0x40)
300 if (module_info _ channels
== 2) {
301 if (UBYTE(module
[0x306 + last_pos
]) < 0xb0
302 || UBYTE(module
[0x35b + last_pos
]) < 0x40
303 || UBYTE(module
[0x3b0 + last_pos
]) < 0x40)
307 module_info _ songs
= 0;
308 parse_cmc_song(module_info
, module
, 0);
309 for (pos
= 0; pos
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++)
310 if (UBYTE(module
[0x206 + pos
]) == 0x8f || UBYTE(module
[0x206 + pos
]) == 0xef)
311 parse_cmc_song(module_info
, module
, pos
+ 1);
315 PRIVATE
FUNC(abool
, is_dlt_track_empty
, (P(CONST BYTEARRAY
, module
), P(int, pos
)))
317 return UBYTE(module
[0x2006 + pos
]) >= 0x43
318 && UBYTE(module
[0x2106 + pos
]) >= 0x40
319 && UBYTE(module
[0x2206 + pos
]) >= 0x40
320 && UBYTE(module
[0x2306 + pos
]) >= 0x40;
323 PRIVATE
FUNC(abool
, is_dlt_pattern_end
, (P(CONST BYTEARRAY
, module
), P(int, pos
), P(int, i
)))
326 for (ch
= 0; ch
< 4; ch
++) {
327 V(int, pattern
) = UBYTE(module
[0x2006 + (ch
<< 8) + pos
]);
329 V(int, offset
) = 6 + (pattern
<< 7) + (i
<< 1);
330 if ((module
[offset
] & 0x80) == 0 && (module
[offset
+ 1] & 0x80) != 0)
337 PRIVATE
FUNC(void, parse_dlt_song
, (
338 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
339 P(BOOLARRAY
, seen
), P(int, pos
)))
341 V(int, player_calls
) = 0;
342 V(abool
, loop
) = FALSE
;
344 while (pos
< 128 && !seen
[pos
] && is_dlt_track_empty(module
, pos
))
346 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
354 p1
= module
[0x2006 + pos
];
355 if (p1
== 0x40 || is_dlt_track_empty(module
, pos
))
358 pos
= UBYTE(module
[0x2086 + pos
]);
360 tempo
= UBYTE(module
[0x2086 + pos
++]);
363 for (i
= 0; i
< 64 && !is_dlt_pattern_end(module
, pos
, i
); i
++)
364 player_calls
+= tempo
;
368 if (player_calls
> 0) {
369 module_info _ loops
[module_info _ songs
] = loop
;
370 set_song_duration(module_info
, player_calls
);
374 PRIVATE
FUNC(abool
, parse_dlt
, (
375 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
376 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
379 NEW_ARRAY(abool
, seen
, 128);
380 if (module_len
== 0x2c06) {
382 ast _ memory
[0x4c00] = 0;
384 else if (module_len
!= 0x2c07)
386 module_info _ type
= ASAP_TYPE_DLT
;
387 if (!load_native(ast
, module_info
, module
, module_len
, GET_PLAYER(dlt
))
388 || module_info _ music
!= 0x2000) {
392 module_info _ songs
= 0;
393 for (pos
= 0; pos
< 128 && module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
395 parse_dlt_song(module_info
, module
, seen
, pos
);
397 return module_info _ songs
> 0;
400 PRIVATE
FUNC(void, parse_mpt_song
, (
401 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
402 P(BOOLARRAY
, global_seen
), P(int, song_len
), P(int, pos
)))
404 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
405 V(int, tempo
) = UBYTE(module
[0x1cf]);
406 V(int, player_calls
) = 0;
407 NEW_ARRAY(byte
, seen
, 256);
408 NEW_ARRAY(int, pattern_offset
, 4);
409 NEW_ARRAY(int, blank_rows
, 4);
410 NEW_ARRAY(int, blank_rows_counter
, 4);
412 INIT_ARRAY(blank_rows
);
413 while (pos
< song_len
) {
416 V(int, pattern_rows
);
417 if (seen
[pos
] != 0) {
418 if (seen
[pos
] != SEEN_THIS_CALL
)
419 module_info _ loops
[module_info _ songs
] = TRUE
;
422 seen
[pos
] = SEEN_THIS_CALL
;
423 global_seen
[pos
] = TRUE
;
424 i
= UBYTE(module
[0x1d0 + pos
* 2]);
426 pos
= UBYTE(module
[0x1d1 + pos
* 2]);
429 for (ch
= 3; ch
>= 0; ch
--) {
430 i
= UBYTE(module
[0x1c6 + ch
]) + (UBYTE(module
[0x1ca + ch
]) << 8) - addr_to_offset
;
431 i
= UBYTE(module
[i
+ pos
* 2]);
435 i
= UWORD(module
, 0x46 + i
);
436 pattern_offset
[ch
] = i
== 0 ? 0 : i
- addr_to_offset
;
437 blank_rows_counter
[ch
] = 0;
441 for (i
= 0; i
< song_len
; i
++)
442 if (seen
[i
] == SEEN_THIS_CALL
)
443 seen
[i
] = SEEN_BEFORE
;
444 for (pattern_rows
= UBYTE(module
[0x1ce]); --pattern_rows
>= 0; ) {
445 for (ch
= 3; ch
>= 0; ch
--) {
446 if (pattern_offset
[ch
] == 0 || --blank_rows_counter
[ch
] >= 0)
449 i
= UBYTE(module
[pattern_offset
[ch
]++]);
450 if (i
< 0x40 || i
== 0xfe)
455 blank_rows
[ch
] = i
- 0x80;
466 blank_rows_counter
[ch
] = blank_rows
[ch
];
468 player_calls
+= tempo
;
472 if (player_calls
> 0)
473 set_song_duration(module_info
, player_calls
);
476 PRIVATE
FUNC(abool
, parse_mpt
, (
477 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
478 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
483 /* seen[i] == TRUE if the track position i has been processed */
484 NEW_ARRAY(abool
, global_seen
, 256);
485 if (module_len
< 0x1d0)
487 module_info _ type
= ASAP_TYPE_MPT
;
488 if (!load_native(ast
, module_info
, module
, module_len
, GET_PLAYER(mpt
)))
490 track0_addr
= UWORD(module
, 2) + 0x1ca;
491 if (UBYTE(module
[0x1c6]) + (UBYTE(module
[0x1ca]) << 8) != track0_addr
)
493 /* Calculate the length of the first track. Address of the second track minus
494 address of the first track equals the length of the first track in bytes.
495 Divide by two to get number of track positions. */
496 song_len
= (UBYTE(module
[0x1c7]) + (UBYTE(module
[0x1cb]) << 8) - track0_addr
) >> 1;
499 INIT_ARRAY(global_seen
);
500 module_info _ songs
= 0;
501 for (pos
= 0; pos
< song_len
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
502 if (!global_seen
[pos
]) {
503 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
504 parse_mpt_song(module_info
, module
, global_seen
, song_len
, pos
);
507 return module_info _ songs
> 0;
510 CONST_ARRAY(byte
, rmt_volume_silent
)
511 16, 8, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1
514 PRIVATE
FUNC(int, rmt_instrument_frames
, (
515 P(CONST BYTEARRAY
, module
), P(int, instrument
),
516 P(int, volume
), P(int, volume_frame
), P(abool
, extra_pokey
)))
518 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
519 V(int, per_frame
) = module
[0xc];
521 V(int, player_calls
);
525 V(int, volume_slide_depth
);
527 V(int, volume_slide
);
528 V(abool
, silent_loop
);
529 instrument
= UWORD(module
, 0xe) - addr_to_offset
+ (instrument
<< 1);
530 if (module
[instrument
+ 1] == 0)
532 instrument
= UWORD(module
, instrument
) - addr_to_offset
;
533 player_calls
= player_call
= volume_frame
* per_frame
;
534 index
= UBYTE(module
[instrument
]) + 1 + player_call
* 3;
535 index_end
= UBYTE(module
[instrument
+ 2]) + 3;
536 index_loop
= UBYTE(module
[instrument
+ 3]);
537 if (index_loop
>= index_end
)
538 return 0; /* error */
539 volume_slide_depth
= UBYTE(module
[instrument
+ 6]);
540 volume_min
= UBYTE(module
[instrument
+ 7]);
541 if (index
>= index_end
)
542 index
= (index
- index_end
) % (index_end
- index_loop
) + index_loop
;
545 V(int, vol
) = module
[instrument
+ index
];
548 if ((vol
& 0xf) >= rmt_volume_silent
[volume
])
549 player_calls
= player_call
+ 1;
552 } while (index
< index_end
);
554 if (volume_slide_depth
== 0)
555 return player_calls
/ per_frame
;
560 if (index
>= index_end
) {
566 vol
= module
[instrument
+ index
];
569 if ((vol
& 0xf) >= rmt_volume_silent
[volume
]) {
570 player_calls
= player_call
+ 1;
575 volume_slide
-= volume_slide_depth
;
576 if (volume_slide
< 0) {
578 if (--volume
<= volume_min
)
582 return player_calls
/ per_frame
;
585 PRIVATE
FUNC(void, parse_rmt_song
, (
586 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
587 P(BOOLARRAY
, global_seen
), P(int, song_len
), P(int, pos_shift
), P(int, pos
)))
590 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
591 V(int, tempo
) = UBYTE(module
[0xb]);
593 V(int, song_offset
) = UWORD(module
, 0x14) - addr_to_offset
;
594 V(int, pattern_lo_offset
) = UWORD(module
, 0x10) - addr_to_offset
;
595 V(int, pattern_hi_offset
) = UWORD(module
, 0x12) - addr_to_offset
;
596 V(int, instrument_frames
);
597 NEW_ARRAY(byte
, seen
, 256);
598 NEW_ARRAY(int, pattern_begin
, 8);
599 NEW_ARRAY(int, pattern_offset
, 8);
600 NEW_ARRAY(int, blank_rows
, 8);
601 NEW_ARRAY(int, instrument_no
, 8);
602 NEW_ARRAY(int, instrument_frame
, 8);
603 NEW_ARRAY(int, volume_value
, 8);
604 NEW_ARRAY(int, volume_frame
, 8);
606 INIT_ARRAY(instrument_no
);
607 INIT_ARRAY(instrument_frame
);
608 INIT_ARRAY(volume_value
);
609 INIT_ARRAY(volume_frame
);
610 while (pos
< song_len
) {
612 V(int, pattern_rows
);
613 if (seen
[pos
] != 0) {
614 if (seen
[pos
] != SEEN_THIS_CALL
)
615 module_info _ loops
[module_info _ songs
] = TRUE
;
618 seen
[pos
] = SEEN_THIS_CALL
;
619 global_seen
[pos
] = TRUE
;
620 if (UBYTE(module
[song_offset
+ (pos
<< pos_shift
)]) == 0xfe) {
621 pos
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + 1]);
624 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
625 i
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + ch
]);
627 blank_rows
[ch
] = 256;
629 pattern_offset
[ch
] = pattern_begin
[ch
] = UBYTE(module
[pattern_lo_offset
+ i
])
630 + (UBYTE(module
[pattern_hi_offset
+ i
]) << 8) - addr_to_offset
;
634 for (i
= 0; i
< song_len
; i
++)
635 if (seen
[i
] == SEEN_THIS_CALL
)
636 seen
[i
] = SEEN_BEFORE
;
637 for (pattern_rows
= UBYTE(module
[0xa]); --pattern_rows
>= 0; ) {
638 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
639 if (--blank_rows
[ch
] > 0)
642 i
= UBYTE(module
[pattern_offset
[ch
]++]);
643 if ((i
& 0x3f) < 62) {
644 i
+= UBYTE(module
[pattern_offset
[ch
]++]) << 8;
645 if ((i
& 0x3f) != 61) {
646 instrument_no
[ch
] = i
>> 10;
647 instrument_frame
[ch
] = frames
;
649 volume_value
[ch
] = (i
>> 6) & 0xf;
650 volume_frame
[ch
] = frames
;
654 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
657 if ((i
& 0x3f) == 62) {
658 blank_rows
[ch
] = i
>> 6;
661 if ((i
& 0xbf) == 63) {
662 tempo
= UBYTE(module
[pattern_offset
[ch
]++]);
666 pattern_offset
[ch
] = pattern_begin
[ch
] + UBYTE(module
[pattern_offset
[ch
]]);
669 /* assert(i == 0xff); */
673 if (pattern_rows
< 0)
676 if (pattern_rows
>= 0)
681 instrument_frames
= 0;
682 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
683 V(int, frame
) = instrument_frame
[ch
];
684 frame
+= rmt_instrument_frames(module
, instrument_no
[ch
], volume_value
[ch
], volume_frame
[ch
] - frame
, ch
>= 4);
685 if (instrument_frames
< frame
)
686 instrument_frames
= frame
;
688 if (frames
> instrument_frames
) {
689 if (frames
- instrument_frames
> 100)
690 module_info _ loops
[module_info _ songs
] = FALSE
;
691 frames
= instrument_frames
;
694 set_song_duration(module_info
, frames
);
697 PRIVATE
FUNC(abool
, parse_rmt
, (
698 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
699 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
705 NEW_ARRAY(abool
, global_seen
, 256);
706 if (module_len
< 0x30 || module
[6] != CHARCODE('R') || module
[7] != CHARCODE('M')
707 || module
[8] != CHARCODE('T') || module
[0xd] != 1)
709 switch (CAST(char) module
[9]) {
714 module_info _ channels
= 2;
720 per_frame
= module
[0xc];
721 if (per_frame
< 1 || per_frame
> 4)
723 module_info _ type
= ASAP_TYPE_RMT
;
724 if (!load_native(ast
, module_info
, module
, module_len
,
725 module_info _ channels
== 2 ? GET_PLAYER(rmt8
) : GET_PLAYER(rmt4
)))
727 song_len
= UWORD(module
, 4) + 1 - UWORD(module
, 0x14);
728 if (pos_shift
== 3 && (song_len
& 4) != 0
729 && UBYTE(module
[6 + UWORD(module
, 4) - UWORD(module
, 2) - 3]) == 0xfe)
731 song_len
>>= pos_shift
;
732 if (song_len
>= 0x100)
734 INIT_ARRAY(global_seen
);
735 module_info _ songs
= 0;
736 for (pos
= 0; pos
< song_len
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
737 if (!global_seen
[pos
]) {
738 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
739 parse_rmt_song(module_info
, module
, global_seen
, song_len
, pos_shift
, pos
);
742 /* must set fastplay after song durations calculations, so they assume 312 */
743 module_info _ fastplay
= perframe2fastplay
[per_frame
- 1];
744 module_info _ player
= 0x600;
745 return module_info _ songs
> 0;
748 PRIVATE
FUNC(void, parse_tmc_song
, (
749 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
751 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
752 V(int, tempo
) = UBYTE(module
[0x24]) + 1;
754 NEW_ARRAY(int, pattern_offset
, 8);
755 NEW_ARRAY(int, blank_rows
, 8);
756 while (UBYTE(module
[0x1a6 + 15 + pos
]) < 0x80) {
758 V(int, pattern_rows
);
759 for (ch
= 7; ch
>= 0; ch
--) {
760 V(int, pat
) = UBYTE(module
[0x1a6 + 15 + pos
- 2 * ch
]);
761 pattern_offset
[ch
] = UBYTE(module
[0xa6 + pat
]) + (UBYTE(module
[0x126 + pat
]) << 8) - addr_to_offset
;
764 for (pattern_rows
= 64; --pattern_rows
>= 0; ) {
765 for (ch
= 7; ch
>= 0; ch
--) {
766 if (--blank_rows
[ch
] >= 0)
769 V(int, i
) = UBYTE(module
[pattern_offset
[ch
]++]);
771 pattern_offset
[ch
]++;
775 i
= UBYTE(module
[pattern_offset
[ch
]++]);
779 tempo
= (i
& 0x7f) + 1;
781 pattern_offset
[ch
]++;
785 i
= module
[pattern_offset
[ch
]++] & 0x7f;
790 pattern_offset
[ch
]++;
795 blank_rows
[ch
] = i
- 0xbf;
803 if (UBYTE(module
[0x1a6 + 14 + pos
]) < 0x80)
804 module_info _ loops
[module_info _ songs
] = TRUE
;
805 set_song_duration(module_info
, frames
);
808 PRIVATE
FUNC(abool
, parse_tmc
, (
809 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
810 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
814 if (module_len
< 0x1d0)
816 module_info _ type
= ASAP_TYPE_TMC
;
817 if (!load_native(ast
, module_info
, module
, module_len
, GET_PLAYER(tmc
)))
819 module_info _ channels
= 2;
821 /* find first instrument */
822 while (module
[0x66 + i
] == 0) {
824 return FALSE
; /* no instrument */
826 last_pos
= (UBYTE(module
[0x66 + i
]) << 8) + UBYTE(module
[0x26 + i
])
827 - UWORD(module
, 2) - 0x1b0;
828 if (0x1b5 + last_pos
>= module_len
)
830 /* skip trailing jumps */
833 return FALSE
; /* no pattern to play */
835 } while (UBYTE(module
[0x1b5 + last_pos
]) >= 0x80);
836 module_info _ songs
= 0;
837 parse_tmc_song(module_info
, module
, 0);
838 for (i
= 0; i
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; i
+= 16)
839 if (UBYTE(module
[0x1b5 + i
]) >= 0x80)
840 parse_tmc_song(module_info
, module
, i
+ 16);
841 /* must set fastplay after song durations calculations, so they assume 312 */
846 ast _ tmc_per_frame
= module
[0x25];
847 module_info _ fastplay
= perframe2fastplay
[i
- 1];
851 PRIVATE
FUNC(void, parse_tm2_song
, (
852 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
854 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
855 V(int, tempo
) = UBYTE(module
[0x24]) + 1;
856 V(int, player_calls
) = 0;
857 NEW_ARRAY(int, pattern_offset
, 8);
858 NEW_ARRAY(int, blank_rows
, 8);
861 V(int, pattern_rows
) = UBYTE(module
[0x386 + 16 + pos
]);
862 if (pattern_rows
== 0)
864 if (pattern_rows
>= 0x80) {
865 module_info _ loops
[module_info _ songs
] = TRUE
;
868 for (ch
= 7; ch
>= 0; ch
--) {
869 V(int, pat
) = UBYTE(module
[0x386 + 15 + pos
- 2 * ch
]);
870 pattern_offset
[ch
] = UBYTE(module
[0x106 + pat
]) + (UBYTE(module
[0x206 + pat
]) << 8) - addr_to_offset
;
873 while (--pattern_rows
>= 0) {
874 for (ch
= 7; ch
>= 0; ch
--) {
875 if (--blank_rows
[ch
] >= 0)
878 V(int, i
) = UBYTE(module
[pattern_offset
[ch
]++]);
880 pattern_offset
[ch
]++;
884 if (UBYTE(module
[pattern_offset
[ch
]++]) >= 0x80)
885 pattern_offset
[ch
]++;
889 pattern_offset
[ch
]++;
893 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
903 pattern_offset
[ch
]++;
907 pattern_offset
[ch
] += 2;
911 blank_rows
[ch
] = i
- 0xf0;
918 player_calls
+= tempo
;
922 set_song_duration(module_info
, player_calls
);
925 PRIVATE
FUNC(abool
, parse_tm2
, (
926 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
927 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
932 if (module_len
< 0x3a4)
934 module_info _ type
= ASAP_TYPE_TM2
;
935 if (!load_native(ast
, module_info
, module
, module_len
, GET_PLAYER(tm2
)))
940 module_info _ fastplay
= perframe2fastplay
[i
- 1];
941 module_info _ player
= 0x500;
942 if (module
[0x1f] != 0)
943 module_info _ channels
= 2;
945 for (i
= 0; i
< 0x80; i
++) {
946 V(int, instr_addr
) = UBYTE(module
[0x86 + i
]) + (UBYTE(module
[0x306 + i
]) << 8);
947 if (instr_addr
!= 0 && instr_addr
< last_pos
)
948 last_pos
= instr_addr
;
950 for (i
= 0; i
< 0x100; i
++) {
951 V(int, pattern_addr
) = UBYTE(module
[0x106 + i
]) + (UBYTE(module
[0x206 + i
]) << 8);
952 if (pattern_addr
!= 0 && pattern_addr
< last_pos
)
953 last_pos
= pattern_addr
;
955 last_pos
-= UWORD(module
, 2) + 0x380;
956 if (0x386 + last_pos
>= module_len
)
958 /* skip trailing stop/jump commands */
963 c
= UBYTE(module
[0x386 + 16 + last_pos
]);
964 } while (c
== 0 || c
>= 0x80);
965 module_info _ songs
= 0;
966 parse_tm2_song(module_info
, module
, 0);
967 for (i
= 0; i
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; i
+= 17) {
968 c
= UBYTE(module
[0x386 + 16 + i
]);
969 if (c
== 0 || c
>= 0x80)
970 parse_tm2_song(module_info
, module
, i
+ 17);
975 #endif /* ASAP_ONLY_SAP */
977 PRIVATE
FUNC(abool
, has_string_at
, (P(CONST BYTEARRAY
, module
), P(int, module_index
), P(STRING
, s
)))
980 V(int, n
) = strlen(s
);
981 for (i
= 0; i
< n
; i
++)
982 if (module
[module_index
+ i
] != CHARCODEAT(s
, i
))
987 PRIVATE
FUNC(STRING
, parse_text
, (P(OUT_STRING
, dest
), P(CONST BYTEARRAY
, module
), P(int, module_index
)))
990 if (module
[module_index
] != CHARCODE('"'))
992 if (has_string_at(module
, module_index
+ 1, "<?>\""))
995 V(int, c
) = module
[module_index
+ 1 + i
];
996 if (c
== CHARCODE('"'))
998 if (c
< 32 || c
>= 127)
1001 BYTES_TO_STRING(dest
, module
, module_index
+ 1, i
);
1005 PRIVATE
FUNC(int, parse_dec
, (P(CONST BYTEARRAY
, module
), P(int, module_index
), P(int, maxval
)))
1008 if (module
[module_index
] == 0xd)
1011 V(int, c
) = module
[module_index
++];
1014 if (c
< CHARCODE('0') || c
> CHARCODE('9'))
1016 r
= 10 * r
+ c
- 48;
1023 PRIVATE
FUNC(int, parse_hex
, (P(CONST BYTEARRAY
, module
), P(int, module_index
)))
1026 if (module
[module_index
] == 0xd)
1029 V(int, c
) = module
[module_index
++];
1035 if (c
>= CHARCODE('0') && c
<= CHARCODE('9'))
1036 r
+= c
- CHARCODE('0');
1037 else if (c
>= CHARCODE('A') && c
<= CHARCODE('F'))
1038 r
+= c
- CHARCODE('A') + 10;
1039 else if (c
>= CHARCODE('a') && c
<= CHARCODE('f'))
1040 r
+= c
- CHARCODE('a') + 10;
1047 FUNC(int, ASAP_ParseDuration
, (P(STRING
, s
)))
1052 V(int, n
) = strlen(s
);
1053 #define PARSE_DIGIT(maxdig, retifnot) \
1056 d = CHARCODEAT(s, i) - 48; \
1057 if (d < 0 || d > maxdig) \
1064 d
= CHARCODEAT(s
, i
) - 48;
1065 if (d
>= 0 && d
<= 9) {
1069 if (i
< n
&& CHARAT(s
, i
) == ':') {
1072 r
= (6 * r
+ d
) * 10;
1080 if (CHARAT(s
, i
) != '.')
1092 PRIVATE
FUNC(abool
, parse_sap_header
, (
1093 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1095 V(int, module_index
);
1097 V(int, duration_index
) = 0;
1098 if (!has_string_at(module
, 0, "SAP\r\n"))
1100 module_info _ fastplay
= -1;
1102 while (UBYTE(module
[module_index
]) != 0xff) {
1103 if (module_index
+ 8 >= module_len
)
1105 #define TAG_IS(s) has_string_at(module, module_index, s)
1107 #define SET_TEXT(v, i) if (parse_text(v, module, module_index + i) == NULL) return FALSE
1109 #define SET_TEXT(v, i) v = parse_text(v, module, module_index + i); if (v == NULL) return FALSE
1111 #define SET_DEC(v, i, min, max) v = parse_dec(module, module_index + i, max); if (v < min) return FALSE
1112 #define SET_HEX(v, i) v = parse_hex(module, module_index + i)
1113 if (TAG_IS("AUTHOR ")) {
1114 SET_TEXT(module_info _ author
, 7);
1116 else if (TAG_IS("NAME ")) {
1117 SET_TEXT(module_info _ name
, 5);
1119 else if (TAG_IS("DATE ")) {
1120 SET_TEXT(module_info _ date
, 5);
1122 else if (TAG_IS("SONGS ")) {
1123 SET_DEC(module_info _ songs
, 6, 1, ASAP_SONGS_MAX
);
1125 else if (TAG_IS("DEFSONG ")) {
1126 SET_DEC(module_info _ default_song
, 8, 0, ASAP_SONGS_MAX
- 1);
1128 else if (TAG_IS("STEREO\r"))
1129 module_info _ channels
= 2;
1130 else if (TAG_IS("NTSC\r"))
1131 module_info _ ntsc
= TRUE
;
1132 else if (TAG_IS("TIME ")) {
1135 char s
[ASAP_DURATION_CHARS
];
1140 for (i
= 0; module
[module_index
+ i
] != 0xd; i
++) { }
1141 if (i
> 5 && has_string_at(module
, module_index
+ i
- 5, " LOOP")) {
1142 module_info _ loops
[duration_index
] = TRUE
;
1146 if (i
>= ASAP_DURATION_CHARS
)
1149 BYTES_TO_STRING(s
, module
, module_index
, i
);
1150 i
= ASAP_ParseDuration(s
);
1151 if (i
< 0 || duration_index
>= ASAP_SONGS_MAX
)
1153 module_info _ durations
[duration_index
++] = i
;
1155 else if (TAG_IS("TYPE "))
1156 type
= module
[module_index
+ 5];
1157 else if (TAG_IS("FASTPLAY ")) {
1158 SET_DEC(module_info _ fastplay
, 9, 1, 312);
1160 else if (TAG_IS("MUSIC ")) {
1161 SET_HEX(module_info _ music
, 6);
1163 else if (TAG_IS("INIT ")) {
1164 SET_HEX(module_info _ init
, 5);
1166 else if (TAG_IS("PLAYER ")) {
1167 SET_HEX(module_info _ player
, 7);
1169 else if (TAG_IS("COVOX ")) {
1170 SET_HEX(module_info _ covox_addr
, 6);
1171 if (module_info _ covox_addr
!= 0xd600)
1173 module_info _ channels
= 2;
1176 while (module
[module_index
++] != 0x0d) {
1177 if (module_index
>= module_len
)
1180 if (module
[module_index
++] != 0x0a)
1183 if (module_info _ default_song
>= module_info _ songs
)
1187 if (module_info _ player
< 0 || module_info _ init
< 0)
1189 module_info _ type
= ASAP_TYPE_SAP_B
;
1192 if (module_info _ player
< 0 || module_info _ music
< 0)
1194 module_info _ type
= ASAP_TYPE_SAP_C
;
1197 if (module_info _ init
< 0)
1199 module_info _ type
= ASAP_TYPE_SAP_D
;
1202 if (module_info _ init
< 0)
1204 module_info _ type
= ASAP_TYPE_SAP_S
;
1205 module_info _ fastplay
= 78;
1210 if (module_info _ fastplay
< 0)
1211 module_info _ fastplay
= module_info _ ntsc
? 262 : 312;
1212 else if (module_info _ ntsc
&& module_info _ fastplay
> 262)
1214 if (UBYTE(module
[module_index
+ 1]) != 0xff)
1216 module_info _ header_len
= module_index
;
1220 PRIVATE
FUNC(abool
, parse_sap
, (
1221 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
1222 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1224 V(int, module_index
);
1225 if (!parse_sap_header(module_info
, module
, module_len
))
1229 ZERO_ARRAY(ast _ memory
);
1230 module_index
= module_info _ header_len
+ 2;
1231 while (module_index
+ 5 <= module_len
) {
1232 V(int, start_addr
) = UWORD(module
, module_index
);
1233 V(int, block_len
) = UWORD(module
, module_index
+ 2) + 1 - start_addr
;
1234 if (block_len
<= 0 || module_index
+ block_len
> module_len
)
1237 COPY_ARRAY(ast _ memory
, start_addr
, module
, module_index
, block_len
);
1238 module_index
+= block_len
;
1239 if (module_index
== module_len
)
1241 if (module_index
+ 7 <= module_len
1242 && UBYTE(module
[module_index
]) == 0xff && UBYTE(module
[module_index
+ 1]) == 0xff)
1248 #define ASAP_EXT(c1, c2, c3) ((CHARCODE(c1) + (CHARCODE(c2) << 8) + (CHARCODE(c3) << 16)) | 0x202020)
1250 PRIVATE
FUNC(int, get_packed_ext
, (P(STRING
, filename
)))
1252 V(int, i
) = strlen(filename
);
1255 V(char, c
) = CHARAT(filename
, i
);
1256 if (c
<= ' ' || c
> 'z')
1259 return ext
| 0x202020;
1260 ext
= (ext
<< 8) + CHARCODE(c
);
1265 PRIVATE
FUNC(abool
, is_our_ext
, (P(int, ext
)))
1268 case ASAP_EXT('S', 'A', 'P'):
1269 #ifndef ASAP_ONLY_SAP
1270 case ASAP_EXT('C', 'M', 'C'):
1271 case ASAP_EXT('C', 'M', '3'):
1272 case ASAP_EXT('C', 'M', 'R'):
1273 case ASAP_EXT('C', 'M', 'S'):
1274 case ASAP_EXT('D', 'M', 'C'):
1275 case ASAP_EXT('D', 'L', 'T'):
1276 case ASAP_EXT('M', 'P', 'T'):
1277 case ASAP_EXT('M', 'P', 'D'):
1278 case ASAP_EXT('R', 'M', 'T'):
1279 case ASAP_EXT('T', 'M', 'C'):
1280 case ASAP_EXT('T', 'M', '8'):
1281 case ASAP_EXT('T', 'M', '2'):
1289 FUNC(abool
, ASAP_IsOurFile
, (P(STRING
, filename
)))
1291 V(int, ext
) = get_packed_ext(filename
);
1292 return is_our_ext(ext
);
1295 FUNC(abool
, ASAP_IsOurExt
, (P(STRING
, ext
)))
1297 return strlen(ext
) == 3
1298 && is_our_ext(ASAP_EXT(CHARAT(ext
, 0), CHARAT(ext
, 1), CHARAT(ext
, 2)));
1301 PRIVATE
FUNC(abool
, parse_file
, (
1302 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
1303 P(STRING
, filename
), P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1306 V(int, len
) = strlen(filename
);
1307 V(int, basename
) = 0;
1309 for (i
= 0; i
< len
; i
++) {
1310 V(char, c
) = CHARAT(filename
, i
);
1311 if (c
== '/' || c
== '\\') {
1320 EMPTY_STRING(module_info _ author
);
1321 SUBSTRING(module_info _ name
, filename
, basename
, ext
- basename
);
1322 EMPTY_STRING(module_info _ date
);
1323 module_info _ channels
= 1;
1324 module_info _ songs
= 1;
1325 module_info _ default_song
= 0;
1326 for (i
= 0; i
< ASAP_SONGS_MAX
; i
++) {
1327 module_info _ durations
[i
] = -1;
1328 module_info _ loops
[i
] = FALSE
;
1330 module_info _ ntsc
= FALSE
;
1331 module_info _ fastplay
= 312;
1332 module_info _ music
= -1;
1333 module_info _ init
= -1;
1334 module_info _ player
= -1;
1335 module_info _ covox_addr
= -1;
1336 switch (get_packed_ext(filename
)) {
1337 case ASAP_EXT('S', 'A', 'P'):
1338 return parse_sap(ast
, module_info
, module
, module_len
);
1339 #ifndef ASAP_ONLY_SAP
1340 case ASAP_EXT('C', 'M', 'C'):
1341 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMC
, GET_PLAYER(cmc
));
1342 case ASAP_EXT('C', 'M', '3'):
1343 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CM3
, GET_PLAYER(cm3
));
1344 case ASAP_EXT('C', 'M', 'R'):
1345 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMR
, GET_PLAYER(cmc
));
1346 case ASAP_EXT('C', 'M', 'S'):
1347 module_info _ channels
= 2;
1348 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMS
, GET_PLAYER(cms
));
1349 case ASAP_EXT('D', 'M', 'C'):
1350 module_info _ fastplay
= 156;
1351 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMC
, GET_PLAYER(cmc
));
1352 case ASAP_EXT('D', 'L', 'T'):
1353 return parse_dlt(ast
, module_info
, module
, module_len
);
1354 case ASAP_EXT('M', 'P', 'T'):
1355 return parse_mpt(ast
, module_info
, module
, module_len
);
1356 case ASAP_EXT('M', 'P', 'D'):
1357 module_info _ fastplay
= 156;
1358 return parse_mpt(ast
, module_info
, module
, module_len
);
1359 case ASAP_EXT('R', 'M', 'T'):
1360 return parse_rmt(ast
, module_info
, module
, module_len
);
1361 case ASAP_EXT('T', 'M', 'C'):
1362 case ASAP_EXT('T', 'M', '8'):
1363 return parse_tmc(ast
, module_info
, module
, module_len
);
1364 case ASAP_EXT('T', 'M', '2'):
1365 return parse_tm2(ast
, module_info
, module
, module_len
);
1372 FUNC(abool
, ASAP_GetModuleInfo
, (
1373 P(ASAP_ModuleInfo PTR
, module_info
), P(STRING
, filename
),
1374 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1376 return parse_file(NULL
, module_info
, filename
, module
, module_len
);
1379 #ifndef ASAP_ONLY_INFO
1381 FUNC(abool
, ASAP_Load
, (
1382 P(ASAP_State PTR
, ast
), P(STRING
, filename
),
1383 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1386 ast _ memory
= s_memory
;
1387 ast _ module_info
= &s_module_info
;
1388 ast _ silence_cycles
= 0;
1389 return parse_file(ast
, ast _ module_info
, filename
, module
, module_len
);
1392 FUNC(void, ASAP_DetectSilence
, (P(ASAP_State PTR
, ast
), P(int, seconds
)))
1394 ast _ silence_cycles
= seconds
* ASAP_MAIN_CLOCK(ast
);
1397 PRIVATE
FUNC(void, call_6502
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, max_scanlines
)))
1399 ast _ cpu_pc
= addr
;
1400 /* put a CIM at 0xd20a and a return address on stack */
1401 dPutByte(0xd20a, 0xd2);
1402 dPutByte(0x01fe, 0x09);
1403 dPutByte(0x01ff, 0xd2);
1405 Cpu_RunScanlines(ast
, max_scanlines
);
1408 /* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */
1409 #define SCANLINES_FOR_INIT (50 * 312)
1411 PRIVATE
FUNC(void, call_6502_init
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, a
), P(int, x
), P(int, y
)))
1413 ast _ cpu_a
= a
& 0xff;
1414 ast _ cpu_x
= x
& 0xff;
1415 ast _ cpu_y
= y
& 0xff;
1416 call_6502(ast
, addr
, SCANLINES_FOR_INIT
);
1419 FUNC(void, ASAP_PlaySong
, (P(ASAP_State PTR
, ast
), P(int, song
), P(int, duration
)))
1421 ast _ current_song
= song
;
1422 ast _ current_duration
= duration
;
1423 ast _ blocks_played
= 0;
1424 ast _ silence_cycles_counter
= ast _ silence_cycles
;
1425 ast _ extra_pokey_mask
= ast _ module_info
->channels
> 1 ? 0x10 : 0;
1427 ast _ covox
[0] = CAST(byte
) 0x80;
1428 ast _ covox
[1] = CAST(byte
) 0x80;
1429 ast _ covox
[2] = CAST(byte
) 0x80;
1430 ast _ covox
[3] = CAST(byte
) 0x80;
1431 PokeySound_Initialize(ast
);
1436 ast _ scanline_number
= 0;
1437 ast _ next_scanline_cycle
= 0;
1438 ast _ timer1_cycle
= NEVER
;
1439 ast _ timer2_cycle
= NEVER
;
1440 ast _ timer4_cycle
= NEVER
;
1442 switch (ast _ module_info
->type
) {
1443 case ASAP_TYPE_SAP_B
:
1444 call_6502_init(ast
, ast _ module_info
->init
, song
, 0, 0);
1446 case ASAP_TYPE_SAP_C
:
1447 #ifndef ASAP_ONLY_SAP
1453 call_6502_init(ast
, ast _ module_info
->player
+ 3, 0x70, ast _ module_info
->music
, ast _ module_info
->music
>> 8);
1454 call_6502_init(ast
, ast _ module_info
->player
+ 3, 0x00, song
, 0);
1456 case ASAP_TYPE_SAP_D
:
1457 case ASAP_TYPE_SAP_S
:
1462 ast _ cpu_pc
= ast _ module_info
->init
;
1464 #ifndef ASAP_ONLY_SAP
1466 call_6502_init(ast
, ast _ module_info
->player
+ 0x100, 0x00, 0x00, ast _ module_info
->song_pos
[song
]);
1469 call_6502_init(ast
, ast _ module_info
->player
, 0x00, ast _ module_info
->music
>> 8, ast _ module_info
->music
);
1470 call_6502_init(ast
, ast _ module_info
->player
, 0x02, ast _ module_info
->song_pos
[song
], 0);
1473 call_6502_init(ast
, ast _ module_info
->player
, ast _ module_info
->song_pos
[song
], ast _ module_info
->music
, ast _ module_info
->music
>> 8);
1477 call_6502_init(ast
, ast _ module_info
->player
, 0x70, ast _ module_info
->music
>> 8, ast _ module_info
->music
);
1478 call_6502_init(ast
, ast _ module_info
->player
, 0x00, song
, 0);
1479 ast _ tmc_per_frame_counter
= 1;
1483 ASAP_MutePokeyChannels(ast
, 0);
1486 FUNC(void, ASAP_MutePokeyChannels
, (P(ASAP_State PTR
, ast
), P(int, mask
)))
1488 PokeySound_Mute(ast
, ADDRESSOF ast _ base_pokey
, mask
);
1489 PokeySound_Mute(ast
, ADDRESSOF ast _ extra_pokey
, mask
>> 4);
1492 FUNC(abool
, call_6502_player
, (P(ASAP_State PTR
, ast
)))
1494 V(int, player
) = ast _ module_info
->player
;
1495 PokeySound_StartFrame(ast
);
1496 switch (ast _ module_info
->type
) {
1497 case ASAP_TYPE_SAP_B
:
1498 call_6502(ast
, player
, ast _ module_info
->fastplay
);
1500 case ASAP_TYPE_SAP_C
:
1501 #ifndef ASAP_ONLY_SAP
1507 call_6502(ast
, player
+ 6, ast _ module_info
->fastplay
);
1509 case ASAP_TYPE_SAP_D
:
1511 V(int, s
)= ast _ cpu_s
;
1512 #define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff
1513 #define RETURN_FROM_PLAYER_ADDR 0xd200
1514 /* save 6502 state on 6502 stack */
1515 PUSH_ON_6502_STACK(ast _ cpu_pc
>> 8);
1516 PUSH_ON_6502_STACK(ast _ cpu_pc
& 0xff);
1517 PUSH_ON_6502_STACK(((ast _ cpu_nz
| (ast _ cpu_nz
>> 1)) & 0x80) + ast _ cpu_vdi
+ \
1518 ((ast _ cpu_nz
& 0xff) == 0 ? Z_FLAG
: 0) + ast _ cpu_c
+ 0x20);
1519 PUSH_ON_6502_STACK(ast _ cpu_a
);
1520 PUSH_ON_6502_STACK(ast _ cpu_x
);
1521 PUSH_ON_6502_STACK(ast _ cpu_y
);
1522 /* RTS will jump to 6502 code that restores the state */
1523 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) >> 8);
1524 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) & 0xff);
1526 dPutByte(RETURN_FROM_PLAYER_ADDR
, 0x68); /* PLA */
1527 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 1, 0xa8); /* TAY */
1528 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 2, 0x68); /* PLA */
1529 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 3, 0xaa); /* TAX */
1530 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 4, 0x68); /* PLA */
1531 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 5, 0x40); /* RTI */
1532 ast _ cpu_pc
= player
;
1534 Cpu_RunScanlines(ast
, ast _ module_info
->fastplay
);
1536 case ASAP_TYPE_SAP_S
:
1537 Cpu_RunScanlines(ast
, ast _ module_info
->fastplay
);
1539 V(int, i
) = dGetByte(0x45) - 1;
1542 dPutByte(0xb07b, dGetByte(0xb07b) + 1);
1545 #ifndef ASAP_ONLY_SAP
1547 call_6502(ast
, player
+ 0x103, ast _ module_info
->fastplay
);
1552 call_6502(ast
, player
+ 3, ast _ module_info
->fastplay
);
1555 if (--ast _ tmc_per_frame_counter
<= 0) {
1556 ast _ tmc_per_frame_counter
= ast _ tmc_per_frame
;
1557 call_6502(ast
, player
+ 3, ast _ module_info
->fastplay
);
1560 call_6502(ast
, player
+ 6, ast _ module_info
->fastplay
);
1564 PokeySound_EndFrame(ast
, ast _ module_info
->fastplay
* 114);
1565 if (ast _ silence_cycles
> 0) {
1566 if (PokeySound_IsSilent(ADDRESSOF ast _ base_pokey
)
1567 && PokeySound_IsSilent(ADDRESSOF ast _ extra_pokey
)) {
1568 ast _ silence_cycles_counter
-= ast _ module_info
->fastplay
* 114;
1569 if (ast _ silence_cycles_counter
<= 0)
1573 ast _ silence_cycles_counter
= ast _ silence_cycles
;
1578 FUNC(int, ASAP_GetPosition
, (P(CONST ASAP_State PTR
, ast
)))
1580 return ast _ blocks_played
* 10 / (ASAP_SAMPLE_RATE
/ 100);
1583 FUNC(int, milliseconds_to_blocks
, (P(int, milliseconds
)))
1585 return milliseconds
* (ASAP_SAMPLE_RATE
/ 100) / 10;
1588 #ifndef ACTIONSCRIPT
1590 FUNC(void, ASAP_Seek
, (P(ASAP_State PTR
, ast
), P(int, position
)))
1592 V(int, block
) = milliseconds_to_blocks(position
);
1593 if (block
< ast _ blocks_played
)
1594 ASAP_PlaySong(ast
, ast _ current_song
, ast _ current_duration
);
1595 while (ast _ blocks_played
+ ast _ samples
- ast _ sample_index
< block
) {
1596 ast _ blocks_played
+= ast _ samples
- ast _ sample_index
;
1597 call_6502_player(ast
);
1599 ast _ sample_index
+= block
- ast _ blocks_played
;
1600 ast _ blocks_played
= block
;
1603 PRIVATE
FUNC(void, serialize_int
, (P(BYTEARRAY
, buffer
), P(int, offset
), P(int, value
)))
1605 buffer
[offset
] = TO_BYTE(value
);
1606 buffer
[offset
+ 1] = TO_BYTE(value
>> 8);
1607 buffer
[offset
+ 2] = TO_BYTE(value
>> 16);
1608 buffer
[offset
+ 3] = TO_BYTE(value
>> 24);
1611 FUNC(void, ASAP_GetWavHeader
, (
1612 P(CONST ASAP_State PTR
, ast
), P(BYTEARRAY
, buffer
), P(ASAP_SampleFormat
, format
)))
1614 V(int, use_16bit
) = format
!= ASAP_FORMAT_U8
? 1 : 0;
1615 V(int, block_size
) = ast _ module_info
->channels
<< use_16bit
;
1616 V(int, bytes_per_second
) = ASAP_SAMPLE_RATE
* block_size
;
1617 V(int, total_blocks
) = milliseconds_to_blocks(ast _ current_duration
);
1618 V(int, n_bytes
) = (total_blocks
- ast _ blocks_played
) * block_size
;
1619 buffer
[0] = CAST(byte
) CHARCODE('R');
1620 buffer
[1] = CAST(byte
) CHARCODE('I');
1621 buffer
[2] = CAST(byte
) CHARCODE('F');
1622 buffer
[3] = CAST(byte
) CHARCODE('F');
1623 serialize_int(buffer
, 4, n_bytes
+ 36);
1624 buffer
[8] = CAST(byte
) CHARCODE('W');
1625 buffer
[9] = CAST(byte
) CHARCODE('A');
1626 buffer
[10] = CAST(byte
) CHARCODE('V');
1627 buffer
[11] = CAST(byte
) CHARCODE('E');
1628 buffer
[12] = CAST(byte
) CHARCODE('f');
1629 buffer
[13] = CAST(byte
) CHARCODE('m');
1630 buffer
[14] = CAST(byte
) CHARCODE('t');
1631 buffer
[15] = CAST(byte
) CHARCODE(' ');
1638 buffer
[22] = CAST(byte
) ast _ module_info
->channels
;
1640 serialize_int(buffer
, 24, ASAP_SAMPLE_RATE
);
1641 serialize_int(buffer
, 28, bytes_per_second
);
1642 buffer
[32] = CAST(byte
) block_size
;
1644 buffer
[34] = CAST(byte
) (8 << use_16bit
);
1646 buffer
[36] = CAST(byte
) CHARCODE('d');
1647 buffer
[37] = CAST(byte
) CHARCODE('a');
1648 buffer
[38] = CAST(byte
) CHARCODE('t');
1649 buffer
[39] = CAST(byte
) CHARCODE('a');
1650 serialize_int(buffer
, 40, n_bytes
);
1653 #endif /* ACTIONSCRIPT */
1655 PRIVATE
FUNC(int, ASAP_GenerateAt
, (P(ASAP_State PTR
, ast
), P(VOIDPTR
, buffer
), P(int, buffer_offset
), P(int, buffer_len
), P(ASAP_SampleFormat
, format
)))
1657 V(int, block_shift
);
1658 V(int, buffer_blocks
);
1660 if (ast _ silence_cycles
> 0 && ast _ silence_cycles_counter
<= 0)
1665 block_shift
= (ast _ module_info
->channels
- 1) + (format
!= ASAP_FORMAT_U8
? 1 : 0);
1667 buffer_blocks
= buffer_len
>> block_shift
;
1668 if (ast _ current_duration
> 0) {
1669 V(int, total_blocks
) = milliseconds_to_blocks(ast _ current_duration
);
1670 if (buffer_blocks
> total_blocks
- ast _ blocks_played
)
1671 buffer_blocks
= total_blocks
- ast _ blocks_played
;
1675 V(int, blocks
) = PokeySound_Generate(ast
, CAST(BYTEARRAY
) buffer
,
1676 buffer_offset
+ (block
<< block_shift
), buffer_blocks
- block
, format
);
1677 ast _ blocks_played
+= blocks
;
1679 } while (block
< buffer_blocks
&& call_6502_player(ast
));
1680 return block
<< block_shift
;
1683 FUNC(int, ASAP_Generate
, (P(ASAP_State PTR
, ast
), P(VOIDPTR
, buffer
), P(int, buffer_len
), P(ASAP_SampleFormat
, format
)))
1685 return ASAP_GenerateAt(ast
, buffer
, 0, buffer_len
, format
);
1688 #endif /* ASAP_ONLY_INFO */
1692 abool
ASAP_CanSetModuleInfo(const char *filename
)
1694 int ext
= get_packed_ext(filename
);
1695 return ext
== ASAP_EXT('S', 'A', 'P');
1698 abool
ASAP_ChangeExt(char *filename
, const char *ext
)
1701 while (*filename
!= '\0') {
1702 if (*filename
== '/' || *filename
== '\\')
1704 else if (*filename
== '.')
1705 dest
= filename
+ 1;
1714 static byte
*put_string(byte
*dest
, const char *str
)
1716 while (*str
!= '\0')
1721 static byte
*put_dec(byte
*dest
, int value
)
1724 dest
= put_dec(dest
, value
/ 10);
1727 *dest
++ = '0' + value
;
1731 static byte
*put_text_tag(byte
*dest
, const char *tag
, const char *value
)
1733 dest
= put_string(dest
, tag
);
1737 while (*value
!= '\0') {
1738 if (*value
< ' ' || *value
> 'z' || *value
== '"' || *value
== '`')
1748 static byte
*put_dec_tag(byte
*dest
, const char *tag
, int value
)
1750 dest
= put_string(dest
, tag
);
1751 dest
= put_dec(dest
, value
);
1757 static byte
*start_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1759 dest
= put_string(dest
, "SAP\r\n");
1760 dest
= put_text_tag(dest
, "AUTHOR ", module_info
->author
);
1763 dest
= put_text_tag(dest
, "NAME ", module_info
->name
);
1766 dest
= put_text_tag(dest
, "DATE ", module_info
->date
);
1769 if (module_info
->songs
> 1) {
1770 dest
= put_dec_tag(dest
, "SONGS ", module_info
->songs
);
1771 if (module_info
->default_song
> 0)
1772 dest
= put_dec_tag(dest
, "DEFSONG ", module_info
->default_song
);
1774 if (module_info
->channels
> 1)
1775 dest
= put_string(dest
, "STEREO\r\n");
1779 static char *two_digits(char *s
, int x
)
1781 s
[0] = '0' + x
/ 10;
1782 s
[1] = '0' + x
% 10;
1786 void ASAP_DurationToString(char *s
, int duration
)
1788 if (duration
>= 0 && duration
< 100 * 60 * 1000) {
1789 int seconds
= duration
/ 1000;
1790 s
= two_digits(s
, seconds
/ 60);
1792 s
= two_digits(s
, seconds
% 60);
1794 if (duration
!= 0) {
1796 s
= two_digits(s
, duration
/ 10);
1799 *s
++ = '0' + duration
;
1805 static byte
*put_durations(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1808 for (song
= 0; song
< module_info
->songs
; song
++) {
1809 if (module_info
->durations
[song
] < 0)
1811 dest
= put_string(dest
, "TIME ");
1812 ASAP_DurationToString((char *) dest
, module_info
->durations
[song
]);
1813 while (*dest
!= '\0')
1815 if (module_info
->loops
[song
])
1816 dest
= put_string(dest
, " LOOP");
1823 int ASAP_SetModuleInfo(const ASAP_ModuleInfo
*module_info
, const BYTEARRAY module
, int module_len
, BYTEARRAY out_module
)
1827 if (memcmp(module
, "SAP\r\n", 5) != 0)
1829 dest
= start_sap_header(out_module
, module_info
);
1833 while (i
< module_len
&& module
[i
] != 0xff) {
1834 if (memcmp(module
+ i
, "AUTHOR ", 7) == 0
1835 || memcmp(module
+ i
, "NAME ", 5) == 0
1836 || memcmp(module
+ i
, "DATE ", 5) == 0
1837 || memcmp(module
+ i
, "SONGS ", 6) == 0
1838 || memcmp(module
+ i
, "DEFSONG ", 8) == 0
1839 || memcmp(module
+ i
, "STEREO\r", 7) == 0
1840 || memcmp(module
+ i
, "TIME ", 5) == 0) {
1841 while (i
< module_len
&& module
[i
++] != 0x0a);
1848 } while (i
< module_len
&& b
!= 0x0a);
1851 dest
= put_durations(dest
, module_info
);
1853 memcpy(dest
, module
+ i
, module_len
);
1855 return dest
- out_module
;
1858 #if !defined(ASAP_ONLY_SAP) && !defined(ASAP_ONLY_INFO)
1860 #define RMT_INIT 0x0c80
1861 #define TM2_INIT 0x1080
1863 const char *ASAP_CanConvert(
1864 const char *filename
, const ASAP_ModuleInfo
*module_info
,
1865 const BYTEARRAY module
, int module_len
)
1868 switch (module_info
->type
) {
1869 case ASAP_TYPE_SAP_B
:
1870 if ((module_info
->init
== 0x3fb || module_info
->init
== 0x3f9) && module_info
->player
== 0x503)
1872 if (module_info
->init
== 0x4f3 || module_info
->init
== 0xf4f3 || module_info
->init
== 0x4ef)
1873 return module_info
->fastplay
== 156 ? "mpd" : "mpt";
1874 if (module_info
->init
== RMT_INIT
)
1876 if ((module_info
->init
== 0x4f5 || module_info
->init
== 0xf4f5 || module_info
->init
== 0x4f2)
1877 || ((module_info
->init
== 0x4e7 || module_info
->init
== 0xf4e7 || module_info
->init
== 0x4e4) && module_info
->fastplay
== 156)
1878 || ((module_info
->init
== 0x4e5 || module_info
->init
== 0xf4e5 || module_info
->init
== 0x4e2) && (module_info
->fastplay
== 104 || module_info
->fastplay
== 78)))
1880 if (module_info
->init
== TM2_INIT
)
1883 case ASAP_TYPE_SAP_C
:
1884 if (module_info
->player
== 0x500 || module_info
->player
== 0xf500) {
1885 if (module_info
->fastplay
== 156)
1887 if (module_info
->channels
> 1)
1889 if (module
[module_len
- 170] == 0x1e)
1891 if (module
[module_len
- 909] == 0x30)
1912 static byte
*put_hex_tag(byte
*dest
, const char *tag
, int value
)
1917 dest
= put_string(dest
, tag
);
1918 for (i
= 12; i
>= 0; i
-= 4) {
1919 int digit
= (value
>> i
) & 0xf;
1920 *dest
++ = (byte
) (digit
+ (digit
< 10 ? '0' : 'A' - 10));
1927 static byte
*put_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
, char type
, int music
, int init
, int player
)
1929 dest
= start_sap_header(dest
, module_info
);
1932 dest
= put_string(dest
, "TYPE ");
1936 if (module_info
->fastplay
!= 312)
1937 dest
= put_dec_tag(dest
, "FASTPLAY ", module_info
->fastplay
);
1938 dest
= put_hex_tag(dest
, "MUSIC ", music
);
1939 dest
= put_hex_tag(dest
, "INIT ", init
);
1940 dest
= put_hex_tag(dest
, "PLAYER ", player
);
1941 dest
= put_durations(dest
, module_info
);
1946 const char *filename
, const ASAP_ModuleInfo
*module_info
,
1947 const BYTEARRAY module
, int module_len
, BYTEARRAY out_module
)
1954 static const int tmc_player
[4] = { 3, -9, -10, -10 };
1955 static const int tmc_init
[4] = { -14, -16, -17, -17 };
1956 switch (module_info
->type
) {
1957 case ASAP_TYPE_SAP_B
:
1958 case ASAP_TYPE_SAP_C
:
1959 out_len
= UWORD(module
, module_info
->header_len
+ 4) - UWORD(module
, module_info
->header_len
+ 2) + 7;
1960 if (out_len
< 7 || module_info
->header_len
+ out_len
>= module_len
)
1962 memcpy(out_module
, module
+ module_info
->header_len
, out_len
);
1968 dest
= put_sap_header(out_module
, module_info
, 'C', module_info
->music
, -1, module_info
->player
);
1971 memcpy(dest
, module
, module_len
);
1972 dest
[0] = 0xff; /* some modules start with zeros */
1975 if (module_info
->type
== ASAP_TYPE_CM3
) {
1976 memcpy(dest
, cm3_obx
+ 2, sizeof(cm3_obx
) - 2);
1977 dest
+= sizeof(cm3_obx
) - 2;
1979 else if (module_info
->type
== ASAP_TYPE_CMS
) {
1980 memcpy(dest
, cms_obx
+ 2, sizeof(cms_obx
) - 2);
1981 dest
+= sizeof(cms_obx
) - 2;
1984 memcpy(dest
, cmc_obx
+ 2, sizeof(cmc_obx
) - 2);
1985 if (module_info
->type
== ASAP_TYPE_CMR
)
1986 memcpy(dest
+ 4 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, sizeof(cmr_bass_table
));
1987 dest
+= sizeof(cmc_obx
) - 2;
1989 return dest
- out_module
;
1991 if (module_info
->songs
!= 1) {
1992 addr
= module_info
->player
- 7 - module_info
->songs
;
1993 dest
= put_sap_header(out_module
, module_info
, 'B', -1, module_info
->player
- 7, module_info
->player
+ 0x103);
1996 addr
= module_info
->player
- 5;
1997 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, module_info
->player
+ 0x103);
2001 memcpy(dest
, module
, module_len
);
2002 if (module_len
== 0x2c06) {
2008 *dest
++ = (byte
) addr
;
2009 *dest
++ = (byte
) (addr
>> 8);
2010 *dest
++ = dlt_obx
[4];
2011 *dest
++ = dlt_obx
[5];
2012 if (module_info
->songs
!= 1) {
2013 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
2014 dest
+= module_info
->songs
;
2015 *dest
++ = 0xaa; /* tax */
2016 *dest
++ = 0xbc; /* ldy song2pos,x */
2017 *dest
++ = (byte
) addr
;
2018 *dest
++ = (byte
) (addr
>> 8);
2021 *dest
++ = 0xa0; /* ldy #0 */
2024 *dest
++ = 0x4c; /* jmp init */
2025 *dest
++ = (byte
) module_info
->player
;
2026 *dest
++ = (byte
) ((module_info
->player
>> 8) + 1);
2027 memcpy(dest
, dlt_obx
+ 6, sizeof(dlt_obx
) - 6);
2028 dest
+= sizeof(dlt_obx
) - 6;
2029 return dest
- out_module
;
2031 if (module_info
->songs
!= 1) {
2032 addr
= module_info
->player
- 17 - module_info
->songs
;
2033 dest
= put_sap_header(out_module
, module_info
, 'B', -1, module_info
->player
- 17, module_info
->player
+ 3);
2036 addr
= module_info
->player
- 13;
2037 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, module_info
->player
+ 3);
2041 memcpy(dest
, module
, module_len
);
2043 *dest
++ = (byte
) addr
;
2044 *dest
++ = (byte
) (addr
>> 8);
2045 *dest
++ = mpt_obx
[4];
2046 *dest
++ = mpt_obx
[5];
2047 if (module_info
->songs
!= 1) {
2048 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
2049 dest
+= module_info
->songs
;
2050 *dest
++ = 0x48; /* pha */
2052 *dest
++ = 0xa0; /* ldy #<music */
2053 *dest
++ = (byte
) module_info
->music
;
2054 *dest
++ = 0xa2; /* ldx #>music */
2055 *dest
++ = (byte
) (module_info
->music
>> 8);
2056 *dest
++ = 0xa9; /* lda #0 */
2058 *dest
++ = 0x20; /* jsr player */
2059 *dest
++ = (byte
) module_info
->player
;
2060 *dest
++ = (byte
) (module_info
->player
>> 8);
2061 if (module_info
->songs
!= 1) {
2062 *dest
++ = 0x68; /* pla */
2063 *dest
++ = 0xa8; /* tay */
2064 *dest
++ = 0xbe; /* ldx song2pos,y */
2065 *dest
++ = (byte
) addr
;
2066 *dest
++ = (byte
) (addr
>> 8);
2069 *dest
++ = 0xa2; /* ldx #0 */
2072 *dest
++ = 0xa9; /* lda #2 */
2074 memcpy(dest
, mpt_obx
+ 6, sizeof(mpt_obx
) - 6);
2075 dest
+= sizeof(mpt_obx
) - 6;
2076 return dest
- out_module
;
2078 dest
= put_sap_header(out_module
, module_info
, 'B', -1, RMT_INIT
, module_info
->player
+ 3);
2081 memcpy(dest
, module
, module_len
);
2083 *dest
++ = (byte
) RMT_INIT
;
2084 *dest
++ = (byte
) (RMT_INIT
>> 8);
2085 if (module_info
->songs
!= 1) {
2086 addr
= RMT_INIT
+ 10 + module_info
->songs
;
2087 *dest
++ = (byte
) addr
;
2088 *dest
++ = (byte
) (addr
>> 8);
2089 *dest
++ = 0xa8; /* tay */
2090 *dest
++ = 0xb9; /* lda song2pos,y */
2091 *dest
++ = (byte
) (RMT_INIT
+ 11);
2092 *dest
++ = (byte
) ((RMT_INIT
+ 11) >> 8);
2095 *dest
++ = (byte
) (RMT_INIT
+ 8);
2096 *dest
++ = (byte
) ((RMT_INIT
+ 8) >> 8);
2097 *dest
++ = 0xa9; /* lda #0 */
2100 *dest
++ = 0xa2; /* ldx #<music */
2101 *dest
++ = (byte
) module_info
->music
;
2102 *dest
++ = 0xa0; /* ldy #>music */
2103 *dest
++ = (byte
) (module_info
->music
>> 8);
2104 *dest
++ = 0x4c; /* jmp player */
2105 *dest
++ = (byte
) module_info
->player
;
2106 *dest
++ = (byte
) (module_info
->player
>> 8);
2107 if (module_info
->songs
!= 1) {
2108 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
2109 dest
+= module_info
->songs
;
2111 if (module_info
->channels
== 1) {
2112 memcpy(dest
, rmt4_obx
+ 2, sizeof(rmt4_obx
) - 2);
2113 dest
+= sizeof(rmt4_obx
) - 2;
2116 memcpy(dest
, rmt8_obx
+ 2, sizeof(rmt8_obx
) - 2);
2117 dest
+= sizeof(rmt8_obx
) - 2;
2119 return dest
- out_module
;
2121 player
= module_info
->player
+ tmc_player
[module
[0x25] - 1];
2122 addr
= player
+ tmc_init
[module
[0x25] - 1];
2123 if (module_info
->songs
!= 1)
2125 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, player
);
2128 memcpy(dest
, module
, module_len
);
2130 *dest
++ = (byte
) addr
;
2131 *dest
++ = (byte
) (addr
>> 8);
2132 *dest
++ = tmc_obx
[4];
2133 *dest
++ = tmc_obx
[5];
2134 if (module_info
->songs
!= 1)
2135 *dest
++ = 0x48; /* pha */
2136 *dest
++ = 0xa0; /* ldy #<music */
2137 *dest
++ = (byte
) module_info
->music
;
2138 *dest
++ = 0xa2; /* ldx #>music */
2139 *dest
++ = (byte
) (module_info
->music
>> 8);
2140 *dest
++ = 0xa9; /* lda #$70 */
2142 *dest
++ = 0x20; /* jsr player */
2143 *dest
++ = (byte
) module_info
->player
;
2144 *dest
++ = (byte
) (module_info
->player
>> 8);
2145 if (module_info
->songs
!= 1) {
2146 *dest
++ = 0x68; /* pla */
2147 *dest
++ = 0xaa; /* tax */
2148 *dest
++ = 0xa9; /* lda #0 */
2152 *dest
++ = 0xa9; /* lda #$60 */
2155 switch (module
[0x25]) {
2157 *dest
++ = 0x06; /* asl 0 */
2159 *dest
++ = 0x4c; /* jmp player */
2160 *dest
++ = (byte
) module_info
->player
;
2161 *dest
++ = (byte
) (module_info
->player
>> 8);
2162 *dest
++ = 0xa5; /* lda 0 */
2164 *dest
++ = 0xe6; /* inc 0 */
2166 *dest
++ = 0x4a; /* lsr @ */
2167 *dest
++ = 0x90; /* bcc player+3 */
2169 *dest
++ = 0xb0; /* bcs player+6 */
2174 *dest
++ = 0xa0; /* ldy #1 */
2176 *dest
++ = 0x84; /* sty 0 */
2178 *dest
++ = 0xd0; /* bne player */
2180 *dest
++ = 0xc6; /* dec 0 */
2182 *dest
++ = 0xd0; /* bne player+6 */
2184 *dest
++ = 0xa0; /* ldy #3 */
2185 *dest
++ = module
[0x25];
2186 *dest
++ = 0x84; /* sty 0 */
2188 *dest
++ = 0xd0; /* bne player+3 */
2194 memcpy(dest
, tmc_obx
+ 6, sizeof(tmc_obx
) - 6);
2195 dest
+= sizeof(tmc_obx
) - 6;
2196 return dest
- out_module
;
2198 dest
= put_sap_header(out_module
, module_info
, 'B', -1, TM2_INIT
, module_info
->player
+ 3);
2201 memcpy(dest
, module
, module_len
);
2203 *dest
++ = (byte
) TM2_INIT
;
2204 *dest
++ = (byte
) (TM2_INIT
>> 8);
2205 if (module_info
->songs
!= 1) {
2206 *dest
++ = (byte
) (TM2_INIT
+ 16);
2207 *dest
++ = (byte
) ((TM2_INIT
+ 16) >> 8);
2208 *dest
++ = 0x48; /* pha */
2211 *dest
++ = (byte
) (TM2_INIT
+ 14);
2212 *dest
++ = (byte
) ((TM2_INIT
+ 14) >> 8);
2214 *dest
++ = 0xa0; /* ldy #<music */
2215 *dest
++ = (byte
) module_info
->music
;
2216 *dest
++ = 0xa2; /* ldx #>music */
2217 *dest
++ = (byte
) (module_info
->music
>> 8);
2218 *dest
++ = 0xa9; /* lda #$70 */
2220 *dest
++ = 0x20; /* jsr player */
2221 *dest
++ = (byte
) module_info
->player
;
2222 *dest
++ = (byte
) (module_info
->player
>> 8);
2223 if (module_info
->songs
!= 1) {
2224 *dest
++ = 0x68; /* pla */
2225 *dest
++ = 0xaa; /* tax */
2226 *dest
++ = 0xa9; /* lda #0 */
2230 *dest
++ = 0xa9; /* lda #0 */
2232 *dest
++ = 0xaa; /* tax */
2234 *dest
++ = 0x4c; /* jmp player */
2235 *dest
++ = (byte
) module_info
->player
;
2236 *dest
++ = (byte
) (module_info
->player
>> 8);
2237 memcpy(dest
, tm2_obx
+ 2, sizeof(tm2_obx
) - 2);
2238 dest
+= sizeof(tm2_obx
) - 2;
2239 return dest
- out_module
;
2245 #endif /* !defined(ASAP_ONLY_SAP) && !defined(ASAP_ONLY_INFO) */
2247 static abool
has_two_digits(const char *s
)
2249 return s
[0] >= '0' && s
[0] <= '9' && s
[1] >= '0' && s
[1] <= '9';
2252 /* "DD/MM/YYYY", "MM/YYYY", "YYYY" -> "YYYY" */
2253 abool
ASAP_DateToYear(const char *date
, char *year
)
2255 if (!has_two_digits(date
))
2257 if (date
[2] == '/') {
2259 if (!has_two_digits(date
))
2261 if (date
[2] == '/') {
2263 if (!has_two_digits(date
))
2267 if (!has_two_digits(date
+ 2) || date
[4] != '\0')
2269 memcpy(year
, date
, 5);