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 FUNC(int, ASAP_GetByte
, (P(ASAP_State PTR
, ast
), P(int, addr
)))
28 switch (addr
& 0xff0f) {
30 return PokeySound_GetRandom(ast
, addr
, ast _ cycle
);
32 if ((addr
& ast _ extra_pokey_mask
) != 0) {
33 /* interrupts in the extra POKEY not emulated at the moment */
38 /* just because some SAP files rely on this */
41 return ast _ scanline_number
>> 1;
43 return dGetByte(addr
);
47 FUNC(void, ASAP_PutByte
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, data
)))
49 if ((addr
>> 8) == 0xd2) {
50 if ((addr
& (ast _ extra_pokey_mask
+ 0xf)) == 0xe) {
51 ast _ irqst
|= data
^ 0xff;
52 #define SET_TIMER_IRQ(ch) \
53 if ((data & ast _ irqst & ch) != 0) { \
54 if (ast _ timer##ch##_cycle == NEVER) { \
55 V(int, t) = ast _ base_pokey.tick_cycle##ch; \
56 while (t < ast _ cycle) \
57 t += ast _ base_pokey.period_cycles##ch; \
58 ast _ timer##ch##_cycle = t; \
59 if (ast _ nearest_event_cycle > t) \
60 ast _ nearest_event_cycle = t; \
64 ast _ timer##ch##_cycle = NEVER;
70 PokeySound_PutByte(ast
, addr
, data
);
72 else if ((addr
& 0xff0f) == 0xd40a) {
73 if (ast _ cycle
<= ast _ next_scanline_cycle
- 8)
74 ast _ cycle
= ast _ next_scanline_cycle
- 8;
76 ast _ cycle
= ast _ next_scanline_cycle
+ 106;
78 else if ((addr
& 0xff00) == ast _ module_info
.covox_addr
) {
79 V(PokeyState PTR
, pst
);
81 if (addr
== 0 || addr
== 3)
82 pst
= ADDRESSOF ast _ base_pokey
;
84 pst
= ADDRESSOF ast _ extra_pokey
;
85 pst _ delta_buffer
[CYCLE_TO_SAMPLE(ast _ cycle
)] += (data
- UBYTE(ast _ covox
[addr
])) << DELTA_SHIFT_COVOX
;
86 ast _ covox
[addr
] = CAST(byte
) (data
);
88 else if ((addr
& 0xff1f) == 0xd01f) {
89 V(int, sample
) = CYCLE_TO_SAMPLE(ast _ cycle
);
92 /* NOT data - ast _ consol; reverse to the POKEY sound */
93 delta
= (ast _ consol
- data
) << DELTA_SHIFT_GTIA
;
95 ast _ base_pokey
.delta_buffer
[sample
] += delta
;
96 ast _ extra_pokey
.delta_buffer
[sample
] += delta
;
102 #define UWORD(array, index) (UBYTE(array[index]) + (UBYTE(array[(index) + 1]) << 8))
104 #ifndef ASAP_ONLY_SAP
110 #define CMR_BASS_TABLE_OFFSET 0x70f
112 CONST_ARRAY(byte
, cmr_bass_table
)
113 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E,
114 0x38, 0x35, CAST(byte
) (0x88), 0x7F, 0x79, 0x73, 0x6C, 0x67,
115 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F,
116 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28,
117 0x25, 0x24, 0x21, 0x1F, 0x1E
120 CONST_ARRAY(int, perframe2fastplay
)
121 312, 312 / 2, 312 / 3, 312 / 4
124 /* Loads native module (anything except SAP) and 6502 player routine. */
125 PRIVATE
FUNC(abool
, load_native
, (
126 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
127 P(CONST BYTEARRAY
, module
), P(int, module_len
), P(RESOURCE
, player
)))
129 V(int, player_last_byte
);
130 V(int, music_last_byte
);
132 if ((UBYTE(module
[0]) != 0xff || UBYTE(module
[1]) != 0xff)
133 && (module
[0] != 0 || module
[1] != 0)) /* some CMC and clones start with zeros */
135 module_info _ player
= UWORD(player
, 2);
136 player_last_byte
= UWORD(player
, 4);
137 module_info _ music
= UWORD(module
, 2);
138 if (module_info _ music
<= player_last_byte
)
140 music_last_byte
= UWORD(module
, 4);
141 if (module_info _ music
<= 0xd7ff && music_last_byte
>= 0xd000)
143 block_len
= music_last_byte
+ 1 - module_info _ music
;
144 if (6 + block_len
!= module_len
) {
147 if (module_info _ type
!= ASAP_TYPE_RMT
|| 11 + block_len
> module_len
)
149 /* allow optional info for Raster Music Tracker */
150 info_addr
= UWORD(module
, 6 + block_len
);
151 if (info_addr
!= module_info _ music
+ block_len
)
153 info_len
= UWORD(module
, 8 + block_len
) + 1 - info_addr
;
154 if (10 + block_len
+ info_len
!= module_len
)
158 COPY_ARRAY(ast _ memory
, module_info _ music
, module
, 6, block_len
);
159 COPY_ARRAY(ast _ memory
, module_info _ player
, player
, 6, player_last_byte
+ 1 - module_info _ player
);
164 PRIVATE
FUNC(void, set_song_duration
, (P(ASAP_ModuleInfo PTR
, module_info
), P(int, player_calls
)))
166 module_info _ durations
[module_info _ songs
] = TO_INT(player_calls
* module_info _ fastplay
* 114000.0 / 1773447);
167 module_info _ songs
++;
170 #define SEEN_THIS_CALL 1
171 #define SEEN_BEFORE 2
172 #define SEEN_REPEAT 3
174 PRIVATE
FUNC(void, parse_cmc_song
, (P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
176 V(int, tempo
) = UBYTE(module
[0x19]);
177 V(int, player_calls
) = 0;
178 V(int, rep_start_pos
) = 0;
179 V(int, rep_end_pos
) = 0;
180 V(int, rep_times
) = 0;
181 NEW_ARRAY(byte
, seen
, 0x55);
183 while (pos
>= 0 && pos
< 0x55) {
187 if (pos
== rep_end_pos
&& rep_times
> 0) {
188 for (p1
= 0; p1
< 0x55; p1
++)
189 if (seen
[p1
] == SEEN_THIS_CALL
|| seen
[p1
] == SEEN_REPEAT
)
194 if (seen
[pos
] != 0) {
195 if (seen
[pos
] != SEEN_THIS_CALL
)
196 module_info _ loops
[module_info _ songs
] = TRUE
;
199 seen
[pos
] = SEEN_THIS_CALL
;
200 p1
= UBYTE(module
[0x206 + pos
]);
201 p2
= UBYTE(module
[0x25b + pos
]);
202 p3
= UBYTE(module
[0x2b0 + pos
]);
203 if (p1
== 0xfe || p2
== 0xfe || p3
== 0xfe) {
230 rep_end_pos
= pos
+ p2
;
235 module_info _ loops
[module_info _ songs
] = TRUE
;
238 p2
= rep_times
> 0 ? SEEN_REPEAT
: SEEN_BEFORE
;
239 for (p1
= 0; p1
< 0x55; p1
++)
240 if (seen
[p1
] == SEEN_THIS_CALL
)
241 seen
[p1
] = CAST(byte
) p2
;
242 player_calls
+= tempo
* (module_info _ type
== ASAP_TYPE_CM3
? 48 : 64);
245 set_song_duration(module_info
, player_calls
);
248 PRIVATE
FUNC(abool
, parse_cmc
, (
249 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
250 P(CONST BYTEARRAY
, module
), P(int, module_len
), P(int, type
), P(RESOURCE
, player
)))
254 if (module_len
< 0x306)
256 module_info _ type
= type
;
257 if (!load_native(ast
, module_info
, module
, module_len
, player
))
259 if (ast
!= NULL
&& type
== ASAP_TYPE_CMR
)
260 COPY_ARRAY(ast _ memory
, 0x500 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, 0, sizeof(cmr_bass_table
));
262 while (--last_pos
>= 0) {
263 if (UBYTE(module
[0x206 + last_pos
]) < 0xb0
264 || UBYTE(module
[0x25b + last_pos
]) < 0x40
265 || UBYTE(module
[0x2b0 + last_pos
]) < 0x40)
267 if (module_info _ channels
== 2) {
268 if (UBYTE(module
[0x306 + last_pos
]) < 0xb0
269 || UBYTE(module
[0x35b + last_pos
]) < 0x40
270 || UBYTE(module
[0x3b0 + last_pos
]) < 0x40)
274 module_info _ songs
= 0;
275 parse_cmc_song(module_info
, module
, 0);
276 for (pos
= 0; pos
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++)
277 if (UBYTE(module
[0x206 + pos
]) == 0x8f || UBYTE(module
[0x206 + pos
]) == 0xef)
278 parse_cmc_song(module_info
, module
, pos
+ 1);
282 PRIVATE
FUNC(abool
, is_dlt_track_empty
, (P(CONST BYTEARRAY
, module
), P(int, pos
)))
284 return UBYTE(module
[0x2006 + pos
]) >= 0x43
285 && UBYTE(module
[0x2106 + pos
]) >= 0x40
286 && UBYTE(module
[0x2206 + pos
]) >= 0x40
287 && UBYTE(module
[0x2306 + pos
]) >= 0x40;
290 PRIVATE
FUNC(abool
, is_dlt_pattern_end
, (P(CONST BYTEARRAY
, module
), P(int, pos
), P(int, i
)))
293 for (ch
= 0; ch
< 4; ch
++) {
294 V(int, pattern
) = UBYTE(module
[0x2006 + (ch
<< 8) + pos
]);
296 V(int, offset
) = 6 + (pattern
<< 7) + (i
<< 1);
297 if ((module
[offset
] & 0x80) == 0 && (module
[offset
+ 1] & 0x80) != 0)
304 PRIVATE
FUNC(void, parse_dlt_song
, (
305 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
306 P(BOOLARRAY
, seen
), P(int, pos
)))
308 V(int, player_calls
) = 0;
309 V(abool
, loop
) = FALSE
;
311 while (pos
< 128 && !seen
[pos
] && is_dlt_track_empty(module
, pos
))
313 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
321 p1
= module
[0x2006 + pos
];
322 if (p1
== 0x40 || is_dlt_track_empty(module
, pos
))
325 pos
= UBYTE(module
[0x2086 + pos
]);
327 tempo
= UBYTE(module
[0x2086 + pos
++]);
330 for (i
= 0; i
< 64 && !is_dlt_pattern_end(module
, pos
, i
); i
++)
331 player_calls
+= tempo
;
335 if (player_calls
> 0) {
336 module_info _ loops
[module_info _ songs
] = loop
;
337 set_song_duration(module_info
, player_calls
);
341 PRIVATE
FUNC(abool
, parse_dlt
, (
342 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
343 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
346 NEW_ARRAY(abool
, seen
, 128);
347 if (module_len
== 0x2c06) {
349 ast _ memory
[0x4c00] = 0;
351 else if (module_len
!= 0x2c07)
353 module_info _ type
= ASAP_TYPE_DLT
;
354 if (!load_native(ast
, module_info
, module
, module_len
, GET_RESOURCE(dlt
, obx
))
355 || module_info _ music
!= 0x2000) {
359 module_info _ songs
= 0;
360 for (pos
= 0; pos
< 128 && module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
362 parse_dlt_song(module_info
, module
, seen
, pos
);
364 return module_info _ songs
> 0;
367 PRIVATE
FUNC(void, parse_mpt_song
, (
368 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
369 P(BOOLARRAY
, global_seen
), P(int, song_len
), P(int, pos
)))
371 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
372 V(int, tempo
) = UBYTE(module
[0x1cf]);
373 V(int, player_calls
) = 0;
374 NEW_ARRAY(byte
, seen
, 256);
375 NEW_ARRAY(int, pattern_offset
, 4);
376 NEW_ARRAY(int, blank_rows
, 4);
377 NEW_ARRAY(int, blank_rows_counter
, 4);
379 INIT_ARRAY(blank_rows
);
380 while (pos
< song_len
) {
383 V(int, pattern_rows
);
384 if (seen
[pos
] != 0) {
385 if (seen
[pos
] != SEEN_THIS_CALL
)
386 module_info _ loops
[module_info _ songs
] = TRUE
;
389 seen
[pos
] = SEEN_THIS_CALL
;
390 global_seen
[pos
] = TRUE
;
391 i
= UBYTE(module
[0x1d0 + pos
* 2]);
393 pos
= UBYTE(module
[0x1d1 + pos
* 2]);
396 for (ch
= 3; ch
>= 0; ch
--) {
397 i
= UBYTE(module
[0x1c6 + ch
]) + (UBYTE(module
[0x1ca + ch
]) << 8) - addr_to_offset
;
398 i
= UBYTE(module
[i
+ pos
* 2]);
402 i
= UWORD(module
, 0x46 + i
);
403 pattern_offset
[ch
] = i
== 0 ? 0 : i
- addr_to_offset
;
404 blank_rows_counter
[ch
] = 0;
408 for (i
= 0; i
< song_len
; i
++)
409 if (seen
[i
] == SEEN_THIS_CALL
)
410 seen
[i
] = SEEN_BEFORE
;
411 for (pattern_rows
= UBYTE(module
[0x1ce]); --pattern_rows
>= 0; ) {
412 for (ch
= 3; ch
>= 0; ch
--) {
413 if (pattern_offset
[ch
] == 0 || --blank_rows_counter
[ch
] >= 0)
416 i
= UBYTE(module
[pattern_offset
[ch
]++]);
417 if (i
< 0x40 || i
== 0xfe)
422 blank_rows
[ch
] = i
- 0x80;
433 blank_rows_counter
[ch
] = blank_rows
[ch
];
435 player_calls
+= tempo
;
439 if (player_calls
> 0)
440 set_song_duration(module_info
, player_calls
);
443 PRIVATE
FUNC(abool
, parse_mpt
, (
444 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
445 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
450 /* seen[i] == TRUE if the track position i has been processed */
451 NEW_ARRAY(abool
, global_seen
, 256);
452 if (module_len
< 0x1d0)
454 module_info _ type
= ASAP_TYPE_MPT
;
455 if (!load_native(ast
, module_info
, module
, module_len
, GET_RESOURCE(mpt
, obx
)))
457 track0_addr
= UWORD(module
, 2) + 0x1ca;
458 if (UBYTE(module
[0x1c6]) + (UBYTE(module
[0x1ca]) << 8) != track0_addr
)
460 /* Calculate the length of the first track. Address of the second track minus
461 address of the first track equals the length of the first track in bytes.
462 Divide by two to get number of track positions. */
463 song_len
= (UBYTE(module
[0x1c7]) + (UBYTE(module
[0x1cb]) << 8) - track0_addr
) >> 1;
466 INIT_ARRAY(global_seen
);
467 module_info _ songs
= 0;
468 for (pos
= 0; pos
< song_len
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
469 if (!global_seen
[pos
]) {
470 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
471 parse_mpt_song(module_info
, module
, global_seen
, song_len
, pos
);
474 return module_info _ songs
> 0;
477 CONST_ARRAY(byte
, rmt_volume_silent
)
478 16, 8, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1
481 PRIVATE
FUNC(int, rmt_instrument_frames
, (
482 P(CONST BYTEARRAY
, module
), P(int, instrument
),
483 P(int, volume
), P(int, volume_frame
), P(abool
, extra_pokey
)))
485 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
486 V(int, per_frame
) = module
[0xc];
488 V(int, player_calls
);
492 V(int, volume_slide_depth
);
494 V(int, volume_slide
);
495 V(abool
, silent_loop
);
496 instrument
= UWORD(module
, 0xe) - addr_to_offset
+ (instrument
<< 1);
497 if (module
[instrument
+ 1] == 0)
499 instrument
= UWORD(module
, instrument
) - addr_to_offset
;
500 player_calls
= player_call
= volume_frame
* per_frame
;
501 index
= UBYTE(module
[instrument
]) + 1 + player_call
* 3;
502 index_end
= UBYTE(module
[instrument
+ 2]) + 3;
503 index_loop
= UBYTE(module
[instrument
+ 3]);
504 if (index_loop
>= index_end
)
505 return 0; /* error */
506 volume_slide_depth
= UBYTE(module
[instrument
+ 6]);
507 volume_min
= UBYTE(module
[instrument
+ 7]);
508 if (index
>= index_end
)
509 index
= (index
- index_end
) % (index_end
- index_loop
) + index_loop
;
512 V(int, vol
) = module
[instrument
+ index
];
515 if ((vol
& 0xf) >= rmt_volume_silent
[volume
])
516 player_calls
= player_call
+ 1;
519 } while (index
< index_end
);
521 if (volume_slide_depth
== 0)
522 return player_calls
/ per_frame
;
527 if (index
>= index_end
) {
533 vol
= module
[instrument
+ index
];
536 if ((vol
& 0xf) >= rmt_volume_silent
[volume
]) {
537 player_calls
= player_call
+ 1;
542 volume_slide
-= volume_slide_depth
;
543 if (volume_slide
< 0) {
545 if (--volume
<= volume_min
)
549 return player_calls
/ per_frame
;
552 PRIVATE
FUNC(void, parse_rmt_song
, (
553 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
),
554 P(BOOLARRAY
, global_seen
), P(int, song_len
), P(int, pos_shift
), P(int, pos
)))
557 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
558 V(int, tempo
) = UBYTE(module
[0xb]);
560 V(int, song_offset
) = UWORD(module
, 0x14) - addr_to_offset
;
561 V(int, pattern_lo_offset
) = UWORD(module
, 0x10) - addr_to_offset
;
562 V(int, pattern_hi_offset
) = UWORD(module
, 0x12) - addr_to_offset
;
563 V(int, instrument_frames
);
564 NEW_ARRAY(byte
, seen
, 256);
565 NEW_ARRAY(int, pattern_begin
, 8);
566 NEW_ARRAY(int, pattern_offset
, 8);
567 NEW_ARRAY(int, blank_rows
, 8);
568 NEW_ARRAY(int, instrument_no
, 8);
569 NEW_ARRAY(int, instrument_frame
, 8);
570 NEW_ARRAY(int, volume_value
, 8);
571 NEW_ARRAY(int, volume_frame
, 8);
573 INIT_ARRAY(instrument_no
);
574 INIT_ARRAY(instrument_frame
);
575 INIT_ARRAY(volume_value
);
576 INIT_ARRAY(volume_frame
);
577 while (pos
< song_len
) {
579 V(int, pattern_rows
);
580 if (seen
[pos
] != 0) {
581 if (seen
[pos
] != SEEN_THIS_CALL
)
582 module_info _ loops
[module_info _ songs
] = TRUE
;
585 seen
[pos
] = SEEN_THIS_CALL
;
586 global_seen
[pos
] = TRUE
;
587 if (UBYTE(module
[song_offset
+ (pos
<< pos_shift
)]) == 0xfe) {
588 pos
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + 1]);
591 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
592 i
= UBYTE(module
[song_offset
+ (pos
<< pos_shift
) + ch
]);
594 blank_rows
[ch
] = 256;
596 pattern_offset
[ch
] = pattern_begin
[ch
] = UBYTE(module
[pattern_lo_offset
+ i
])
597 + (UBYTE(module
[pattern_hi_offset
+ i
]) << 8) - addr_to_offset
;
601 for (i
= 0; i
< song_len
; i
++)
602 if (seen
[i
] == SEEN_THIS_CALL
)
603 seen
[i
] = SEEN_BEFORE
;
604 for (pattern_rows
= UBYTE(module
[0xa]); --pattern_rows
>= 0; ) {
605 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
606 if (--blank_rows
[ch
] > 0)
609 i
= UBYTE(module
[pattern_offset
[ch
]++]);
610 if ((i
& 0x3f) < 62) {
611 i
+= UBYTE(module
[pattern_offset
[ch
]++]) << 8;
612 if ((i
& 0x3f) != 61) {
613 instrument_no
[ch
] = i
>> 10;
614 instrument_frame
[ch
] = frames
;
616 volume_value
[ch
] = (i
>> 6) & 0xf;
617 volume_frame
[ch
] = frames
;
621 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
624 if ((i
& 0x3f) == 62) {
625 blank_rows
[ch
] = i
>> 6;
628 if ((i
& 0xbf) == 63) {
629 tempo
= UBYTE(module
[pattern_offset
[ch
]++]);
633 pattern_offset
[ch
] = pattern_begin
[ch
] + UBYTE(module
[pattern_offset
[ch
]]);
636 /* assert(i == 0xff); */
640 if (pattern_rows
< 0)
643 if (pattern_rows
>= 0)
648 instrument_frames
= 0;
649 for (ch
= 0; ch
< 1 << pos_shift
; ch
++) {
650 V(int, frame
) = instrument_frame
[ch
];
651 frame
+= rmt_instrument_frames(module
, instrument_no
[ch
], volume_value
[ch
], volume_frame
[ch
] - frame
, ch
>= 4);
652 if (instrument_frames
< frame
)
653 instrument_frames
= frame
;
655 if (frames
> instrument_frames
) {
656 if (frames
- instrument_frames
> 100)
657 module_info _ loops
[module_info _ songs
] = FALSE
;
658 frames
= instrument_frames
;
661 set_song_duration(module_info
, frames
);
664 PRIVATE
FUNC(abool
, parse_rmt
, (
665 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
666 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
672 NEW_ARRAY(abool
, global_seen
, 256);
673 if (module_len
< 0x30 || module
[6] != CHARCODE('R') || module
[7] != CHARCODE('M')
674 || module
[8] != CHARCODE('T') || module
[0xd] != 1)
676 switch (CAST(char) module
[9]) {
681 module_info _ channels
= 2;
687 per_frame
= module
[0xc];
688 if (per_frame
< 1 || per_frame
> 4)
690 module_info _ type
= ASAP_TYPE_RMT
;
691 if (!load_native(ast
, module_info
, module
, module_len
,
692 module_info _ channels
== 2 ? GET_RESOURCE(rmt8
, obx
) : GET_RESOURCE(rmt4
, obx
)))
694 song_len
= UWORD(module
, 4) + 1 - UWORD(module
, 0x14);
695 if (pos_shift
== 3 && (song_len
& 4) != 0
696 && UBYTE(module
[6 + UWORD(module
, 4) - UWORD(module
, 2) - 3]) == 0xfe)
698 song_len
>>= pos_shift
;
699 if (song_len
>= 0x100)
701 INIT_ARRAY(global_seen
);
702 module_info _ songs
= 0;
703 for (pos
= 0; pos
< song_len
&& module_info _ songs
< ASAP_SONGS_MAX
; pos
++) {
704 if (!global_seen
[pos
]) {
705 module_info _ song_pos
[module_info _ songs
] = CAST(byte
) pos
;
706 parse_rmt_song(module_info
, module
, global_seen
, song_len
, pos_shift
, pos
);
709 /* must set fastplay after song durations calculations, so they assume 312 */
710 module_info _ fastplay
= perframe2fastplay
[per_frame
- 1];
711 module_info _ player
= 0x600;
712 return module_info _ songs
> 0;
715 PRIVATE
FUNC(void, parse_tmc_song
, (
716 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
718 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
719 V(int, tempo
) = UBYTE(module
[0x24]) + 1;
721 NEW_ARRAY(int, pattern_offset
, 8);
722 NEW_ARRAY(int, blank_rows
, 8);
723 while (UBYTE(module
[0x1a6 + 15 + pos
]) < 0x80) {
725 V(int, pattern_rows
);
726 for (ch
= 7; ch
>= 0; ch
--) {
727 V(int, pat
) = UBYTE(module
[0x1a6 + 15 + pos
- 2 * ch
]);
728 pattern_offset
[ch
] = UBYTE(module
[0xa6 + pat
]) + (UBYTE(module
[0x126 + pat
]) << 8) - addr_to_offset
;
731 for (pattern_rows
= 64; --pattern_rows
>= 0; ) {
732 for (ch
= 7; ch
>= 0; ch
--) {
733 if (--blank_rows
[ch
] >= 0)
736 V(int, i
) = UBYTE(module
[pattern_offset
[ch
]++]);
738 pattern_offset
[ch
]++;
742 i
= UBYTE(module
[pattern_offset
[ch
]++]);
746 tempo
= (i
& 0x7f) + 1;
748 pattern_offset
[ch
]++;
752 i
= module
[pattern_offset
[ch
]++] & 0x7f;
757 pattern_offset
[ch
]++;
762 blank_rows
[ch
] = i
- 0xbf;
770 if (UBYTE(module
[0x1a6 + 14 + pos
]) < 0x80)
771 module_info _ loops
[module_info _ songs
] = TRUE
;
772 set_song_duration(module_info
, frames
);
775 PRIVATE
FUNC(abool
, parse_tmc
, (
776 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
777 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
781 if (module_len
< 0x1d0)
783 module_info _ type
= ASAP_TYPE_TMC
;
784 if (!load_native(ast
, module_info
, module
, module_len
, GET_RESOURCE(tmc
, obx
)))
786 module_info _ channels
= 2;
788 /* find first instrument */
789 while (module
[0x66 + i
] == 0) {
791 return FALSE
; /* no instrument */
793 last_pos
= (UBYTE(module
[0x66 + i
]) << 8) + UBYTE(module
[0x26 + i
])
794 - UWORD(module
, 2) - 0x1b0;
795 if (0x1b5 + last_pos
>= module_len
)
797 /* skip trailing jumps */
800 return FALSE
; /* no pattern to play */
802 } while (UBYTE(module
[0x1b5 + last_pos
]) >= 0x80);
803 module_info _ songs
= 0;
804 parse_tmc_song(module_info
, module
, 0);
805 for (i
= 0; i
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; i
+= 16)
806 if (UBYTE(module
[0x1b5 + i
]) >= 0x80)
807 parse_tmc_song(module_info
, module
, i
+ 16);
808 /* must set fastplay after song durations calculations, so they assume 312 */
813 ast _ tmc_per_frame
= module
[0x25];
814 module_info _ fastplay
= perframe2fastplay
[i
- 1];
818 PRIVATE
FUNC(void, parse_tm2_song
, (
819 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, pos
)))
821 V(int, addr_to_offset
) = UWORD(module
, 2) - 6;
822 V(int, tempo
) = UBYTE(module
[0x24]) + 1;
823 V(int, player_calls
) = 0;
824 NEW_ARRAY(int, pattern_offset
, 8);
825 NEW_ARRAY(int, blank_rows
, 8);
828 V(int, pattern_rows
) = UBYTE(module
[0x386 + 16 + pos
]);
829 if (pattern_rows
== 0)
831 if (pattern_rows
>= 0x80) {
832 module_info _ loops
[module_info _ songs
] = TRUE
;
835 for (ch
= 7; ch
>= 0; ch
--) {
836 V(int, pat
) = UBYTE(module
[0x386 + 15 + pos
- 2 * ch
]);
837 pattern_offset
[ch
] = UBYTE(module
[0x106 + pat
]) + (UBYTE(module
[0x206 + pat
]) << 8) - addr_to_offset
;
840 while (--pattern_rows
>= 0) {
841 for (ch
= 7; ch
>= 0; ch
--) {
842 if (--blank_rows
[ch
] >= 0)
845 V(int, i
) = UBYTE(module
[pattern_offset
[ch
]++]);
847 pattern_offset
[ch
]++;
851 if (UBYTE(module
[pattern_offset
[ch
]++]) >= 0x80)
852 pattern_offset
[ch
]++;
856 pattern_offset
[ch
]++;
860 blank_rows
[ch
] = UBYTE(module
[pattern_offset
[ch
]++]);
870 pattern_offset
[ch
]++;
874 pattern_offset
[ch
] += 2;
878 blank_rows
[ch
] = i
- 0xf0;
885 player_calls
+= tempo
;
889 set_song_duration(module_info
, player_calls
);
892 PRIVATE
FUNC(abool
, parse_tm2
, (
893 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
894 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
899 if (module_len
< 0x3a4)
901 module_info _ type
= ASAP_TYPE_TM2
;
902 if (!load_native(ast
, module_info
, module
, module_len
, GET_RESOURCE(tm2
, obx
)))
907 module_info _ fastplay
= perframe2fastplay
[i
- 1];
908 module_info _ player
= 0x500;
909 if (module
[0x1f] != 0)
910 module_info _ channels
= 2;
912 for (i
= 0; i
< 0x80; i
++) {
913 V(int, instr_addr
) = UBYTE(module
[0x86 + i
]) + (UBYTE(module
[0x306 + i
]) << 8);
914 if (instr_addr
!= 0 && instr_addr
< last_pos
)
915 last_pos
= instr_addr
;
917 for (i
= 0; i
< 0x100; i
++) {
918 V(int, pattern_addr
) = UBYTE(module
[0x106 + i
]) + (UBYTE(module
[0x206 + i
]) << 8);
919 if (pattern_addr
!= 0 && pattern_addr
< last_pos
)
920 last_pos
= pattern_addr
;
922 last_pos
-= UWORD(module
, 2) + 0x380;
923 if (0x386 + last_pos
>= module_len
)
925 /* skip trailing stop/jump commands */
930 c
= UBYTE(module
[0x386 + 16 + last_pos
]);
931 } while (c
== 0 || c
>= 0x80);
932 module_info _ songs
= 0;
933 parse_tm2_song(module_info
, module
, 0);
934 for (i
= 0; i
< last_pos
&& module_info _ songs
< ASAP_SONGS_MAX
; i
+= 17) {
935 c
= UBYTE(module
[0x386 + 16 + i
]);
936 if (c
== 0 || c
>= 0x80)
937 parse_tm2_song(module_info
, module
, i
+ 17);
942 #endif /* ASAP_ONLY_SAP */
944 PRIVATE
FUNC(abool
, has_string_at
, (P(CONST BYTEARRAY
, module
), P(int, module_index
), P(STRING
, s
)))
947 V(int, n
) = strlen(s
);
948 for (i
= 0; i
< n
; i
++)
949 if (module
[module_index
+ i
] != CHARCODEAT(s
, i
))
954 PRIVATE
FUNC(STRING
, parse_text
, (P(OUT_STRING
, dest
), P(CONST BYTEARRAY
, module
), P(int, module_index
)))
957 if (module
[module_index
] != CHARCODE('"'))
959 if (has_string_at(module
, module_index
+ 1, "<?>\""))
962 V(int, c
) = module
[module_index
+ 1 + i
];
963 if (c
== CHARCODE('"'))
965 if (c
< 32 || c
>= 127)
968 BYTES_TO_STRING(dest
, module
, module_index
+ 1, i
);
972 PRIVATE
FUNC(int, parse_dec
, (P(CONST BYTEARRAY
, module
), P(int, module_index
), P(int, maxval
)))
975 if (module
[module_index
] == 0xd)
978 V(int, c
) = module
[module_index
++];
981 if (c
< CHARCODE('0') || c
> CHARCODE('9'))
990 PRIVATE
FUNC(int, parse_hex
, (P(CONST BYTEARRAY
, module
), P(int, module_index
)))
993 if (module
[module_index
] == 0xd)
996 V(int, c
) = module
[module_index
++];
1002 if (c
>= CHARCODE('0') && c
<= CHARCODE('9'))
1003 r
+= c
- CHARCODE('0');
1004 else if (c
>= CHARCODE('A') && c
<= CHARCODE('F'))
1005 r
+= c
- CHARCODE('A') + 10;
1006 else if (c
>= CHARCODE('a') && c
<= CHARCODE('f'))
1007 r
+= c
- CHARCODE('a') + 10;
1014 FUNC(int, ASAP_ParseDuration
, (P(STRING
, s
)))
1019 V(int, n
) = strlen(s
);
1020 #define PARSE_DIGIT(maxdig, retifnot) \
1023 d = CHARCODEAT(s, i) - 48; \
1024 if (d < 0 || d > maxdig) \
1031 d
= CHARCODEAT(s
, i
) - 48;
1032 if (d
>= 0 && d
<= 9) {
1036 if (i
< n
&& CHARAT(s
, i
) == ':') {
1039 r
= (6 * r
+ d
) * 10;
1047 if (CHARAT(s
, i
) != '.')
1059 PRIVATE
FUNC(abool
, parse_sap_header
, (
1060 P(ASAP_ModuleInfo PTR
, module_info
), P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1062 V(int, module_index
);
1064 V(int, duration_index
) = 0;
1065 if (!has_string_at(module
, 0, "SAP\r\n"))
1068 while (UBYTE(module
[module_index
]) != 0xff) {
1069 if (module_index
+ 8 >= module_len
)
1071 #define TAG_IS(s) has_string_at(module, module_index, s)
1073 #define SET_TEXT(v, i) if (parse_text(v, module, module_index + i) == NULL) return FALSE
1075 #define SET_TEXT(v, i) v = parse_text(v, module, module_index + i); if (v == NULL) return FALSE
1077 #define SET_DEC(v, i, min, max) v = parse_dec(module, module_index + i, max); if (v < min) return FALSE
1078 #define SET_HEX(v, i) v = parse_hex(module, module_index + i)
1079 if (TAG_IS("AUTHOR ")) {
1080 SET_TEXT(module_info _ author
, 7);
1082 else if (TAG_IS("NAME ")) {
1083 SET_TEXT(module_info _ name
, 5);
1085 else if (TAG_IS("DATE ")) {
1086 SET_TEXT(module_info _ date
, 5);
1088 else if (TAG_IS("SONGS ")) {
1089 SET_DEC(module_info _ songs
, 6, 1, ASAP_SONGS_MAX
);
1091 else if (TAG_IS("DEFSONG ")) {
1092 SET_DEC(module_info _ default_song
, 8, 0, ASAP_SONGS_MAX
- 1);
1094 else if (TAG_IS("STEREO\r"))
1095 module_info _ channels
= 2;
1096 else if (TAG_IS("TIME ")) {
1099 char s
[ASAP_DURATION_CHARS
];
1104 for (i
= 0; module
[module_index
+ i
] != 0xd; i
++);
1105 if (i
> 5 && has_string_at(module
, module_index
+ i
- 5, " LOOP")) {
1106 module_info _ loops
[duration_index
] = TRUE
;
1110 if (i
>= ASAP_DURATION_CHARS
)
1113 BYTES_TO_STRING(s
, module
, module_index
, i
);
1114 i
= ASAP_ParseDuration(s
);
1115 if (i
< 0 || duration_index
>= ASAP_SONGS_MAX
)
1117 module_info _ durations
[duration_index
++] = i
;
1119 else if (TAG_IS("TYPE "))
1120 type
= module
[module_index
+ 5];
1121 else if (TAG_IS("FASTPLAY ")) {
1122 SET_DEC(module_info _ fastplay
, 9, 1, 312);
1124 else if (TAG_IS("MUSIC ")) {
1125 SET_HEX(module_info _ music
, 6);
1127 else if (TAG_IS("INIT ")) {
1128 SET_HEX(module_info _ init
, 5);
1130 else if (TAG_IS("PLAYER ")) {
1131 SET_HEX(module_info _ player
, 7);
1133 else if (TAG_IS("COVOX ")) {
1134 SET_HEX(module_info _ covox_addr
, 6);
1135 if (module_info _ covox_addr
!= 0xd600)
1137 module_info _ channels
= 2;
1140 while (module
[module_index
++] != 0x0d) {
1141 if (module_index
>= module_len
)
1144 if (module
[module_index
++] != 0x0a)
1147 if (module_info _ default_song
>= module_info _ songs
)
1151 if (module_info _ player
< 0 || module_info _ init
< 0)
1153 module_info _ type
= ASAP_TYPE_SAP_B
;
1156 if (module_info _ player
< 0 || module_info _ music
< 0)
1158 module_info _ type
= ASAP_TYPE_SAP_C
;
1161 if (module_info _ init
< 0)
1163 module_info _ type
= ASAP_TYPE_SAP_D
;
1166 if (module_info _ init
< 0)
1168 module_info _ type
= ASAP_TYPE_SAP_S
;
1169 module_info _ fastplay
= 78;
1174 if (UBYTE(module
[module_index
+ 1]) != 0xff)
1176 module_info _ header_len
= module_index
;
1180 PRIVATE
FUNC(abool
, parse_sap
, (
1181 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
1182 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1184 V(int, module_index
);
1185 if (!parse_sap_header(module_info
, module
, module_len
))
1189 ZERO_ARRAY(ast _ memory
);
1190 module_index
= module_info _ header_len
+ 2;
1191 while (module_index
+ 5 <= module_len
) {
1192 V(int, start_addr
) = UWORD(module
, module_index
);
1193 V(int, block_len
) = UWORD(module
, module_index
+ 2) + 1 - start_addr
;
1194 if (block_len
<= 0 || module_index
+ block_len
> module_len
)
1197 COPY_ARRAY(ast _ memory
, start_addr
, module
, module_index
, block_len
);
1198 module_index
+= block_len
;
1199 if (module_index
== module_len
)
1201 if (module_index
+ 7 <= module_len
1202 && UBYTE(module
[module_index
]) == 0xff && UBYTE(module
[module_index
+ 1]) == 0xff)
1208 #define ASAP_EXT(c1, c2, c3) ((CHARCODE(c1) + (CHARCODE(c2) << 8) + (CHARCODE(c3) << 16)) | 0x202020)
1210 PRIVATE
FUNC(int, get_packed_ext
, (P(STRING
, filename
)))
1212 V(int, i
) = strlen(filename
);
1215 V(char, c
) = CHARAT(filename
, i
);
1216 if (c
<= ' ' || c
> 'z')
1219 return ext
| 0x202020;
1220 ext
= (ext
<< 8) + CHARCODE(c
);
1225 PRIVATE
FUNC(abool
, is_our_ext
, (P(int, ext
)))
1228 case ASAP_EXT('S', 'A', 'P'):
1229 #ifndef ASAP_ONLY_SAP
1230 case ASAP_EXT('C', 'M', 'C'):
1231 case ASAP_EXT('C', 'M', '3'):
1232 case ASAP_EXT('C', 'M', 'R'):
1233 case ASAP_EXT('C', 'M', 'S'):
1234 case ASAP_EXT('D', 'M', 'C'):
1235 case ASAP_EXT('D', 'L', 'T'):
1236 case ASAP_EXT('M', 'P', 'T'):
1237 case ASAP_EXT('M', 'P', 'D'):
1238 case ASAP_EXT('R', 'M', 'T'):
1239 case ASAP_EXT('T', 'M', 'C'):
1240 case ASAP_EXT('T', 'M', '8'):
1241 case ASAP_EXT('T', 'M', '2'):
1249 FUNC(abool
, ASAP_IsOurFile
, (P(STRING
, filename
)))
1251 V(int, ext
) = get_packed_ext(filename
);
1252 return is_our_ext(ext
);
1255 FUNC(abool
, ASAP_IsOurExt
, (P(STRING
, ext
)))
1257 return strlen(ext
) == 3
1258 && is_our_ext(ASAP_EXT(CHARAT(ext
, 0), CHARAT(ext
, 1), CHARAT(ext
, 2)));
1261 PRIVATE
FUNC(abool
, parse_file
, (
1262 P(ASAP_State PTR
, ast
), P(ASAP_ModuleInfo PTR
, module_info
),
1263 P(STRING
, filename
), P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1266 V(int, len
) = strlen(filename
);
1267 V(int, basename
) = 0;
1269 for (i
= 0; i
< len
; i
++) {
1270 V(char, c
) = CHARAT(filename
, i
);
1271 if (c
== '/' || c
== '\\') {
1280 EMPTY_STRING(module_info _ author
);
1281 SUBSTRING(module_info _ name
, filename
, basename
, ext
- basename
);
1282 EMPTY_STRING(module_info _ date
);
1283 module_info _ channels
= 1;
1284 module_info _ songs
= 1;
1285 module_info _ default_song
= 0;
1286 for (i
= 0; i
< ASAP_SONGS_MAX
; i
++) {
1287 module_info _ durations
[i
] = -1;
1288 module_info _ loops
[i
] = FALSE
;
1290 module_info _ fastplay
= 312;
1291 module_info _ music
= -1;
1292 module_info _ init
= -1;
1293 module_info _ player
= -1;
1294 module_info _ covox_addr
= -1;
1295 switch (get_packed_ext(filename
)) {
1296 case ASAP_EXT('S', 'A', 'P'):
1297 return parse_sap(ast
, module_info
, module
, module_len
);
1298 #ifndef ASAP_ONLY_SAP
1299 case ASAP_EXT('C', 'M', 'C'):
1300 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMC
, GET_RESOURCE(cmc
, obx
));
1301 case ASAP_EXT('C', 'M', '3'):
1302 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CM3
, GET_RESOURCE(cm3
, obx
));
1303 case ASAP_EXT('C', 'M', 'R'):
1304 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMR
, GET_RESOURCE(cmc
, obx
));
1305 case ASAP_EXT('C', 'M', 'S'):
1306 module_info _ channels
= 2;
1307 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMS
, GET_RESOURCE(cms
, obx
));
1308 case ASAP_EXT('D', 'M', 'C'):
1309 module_info _ fastplay
= 156;
1310 return parse_cmc(ast
, module_info
, module
, module_len
, ASAP_TYPE_CMC
, GET_RESOURCE(cmc
, obx
));
1311 case ASAP_EXT('D', 'L', 'T'):
1312 return parse_dlt(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('M', 'P', 'D'):
1316 module_info _ fastplay
= 156;
1317 return parse_mpt(ast
, module_info
, module
, module_len
);
1318 case ASAP_EXT('R', 'M', 'T'):
1319 return parse_rmt(ast
, module_info
, module
, module_len
);
1320 case ASAP_EXT('T', 'M', 'C'):
1321 case ASAP_EXT('T', 'M', '8'):
1322 return parse_tmc(ast
, module_info
, module
, module_len
);
1323 case ASAP_EXT('T', 'M', '2'):
1324 return parse_tm2(ast
, module_info
, module
, module_len
);
1331 FUNC(abool
, ASAP_GetModuleInfo
, (
1332 P(ASAP_ModuleInfo PTR
, module_info
), P(STRING
, filename
),
1333 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1335 return parse_file(NULL
, module_info
, filename
, module
, module_len
);
1338 FUNC(abool
, ASAP_Load
, (
1339 P(ASAP_State PTR
, ast
), P(STRING
, filename
),
1340 P(CONST BYTEARRAY
, module
), P(int, module_len
)))
1342 ast _ silence_cycles
= 0;
1343 return parse_file(ast
, ADDRESSOF ast _ module_info
, filename
, module
, module_len
);
1346 FUNC(void, ASAP_DetectSilence
, (P(ASAP_State PTR
, ast
), P(int, seconds
)))
1348 ast _ silence_cycles
= seconds
* ASAP_MAIN_CLOCK
;
1351 PRIVATE
FUNC(void, call_6502
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, max_scanlines
)))
1353 ast _ cpu_pc
= addr
;
1354 /* put a CIM at 0xd20a and a return address on stack */
1355 dPutByte(0xd20a, 0xd2);
1356 dPutByte(0x01fe, 0x09);
1357 dPutByte(0x01ff, 0xd2);
1359 Cpu_RunScanlines(ast
, max_scanlines
);
1362 /* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */
1363 #define SCANLINES_FOR_INIT (50 * 312)
1365 PRIVATE
FUNC(void, call_6502_init
, (P(ASAP_State PTR
, ast
), P(int, addr
), P(int, a
), P(int, x
), P(int, y
)))
1367 ast _ cpu_a
= a
& 0xff;
1368 ast _ cpu_x
= x
& 0xff;
1369 ast _ cpu_y
= y
& 0xff;
1370 call_6502(ast
, addr
, SCANLINES_FOR_INIT
);
1373 FUNC(void, ASAP_PlaySong
, (P(ASAP_State PTR
, ast
), P(int, song
), P(int, duration
)))
1375 ast _ current_song
= song
;
1376 ast _ current_duration
= duration
;
1377 ast _ blocks_played
= 0;
1378 ast _ silence_cycles_counter
= ast _ silence_cycles
;
1379 ast _ extra_pokey_mask
= ast _ module_info
.channels
> 1 ? 0x10 : 0;
1381 ast _ covox
[0] = CAST(byte
) 0x80;
1382 ast _ covox
[1] = CAST(byte
) 0x80;
1383 ast _ covox
[2] = CAST(byte
) 0x80;
1384 ast _ covox
[3] = CAST(byte
) 0x80;
1385 PokeySound_Initialize(ast
);
1390 ast _ scanline_number
= 0;
1391 ast _ next_scanline_cycle
= 0;
1392 ast _ timer1_cycle
= NEVER
;
1393 ast _ timer2_cycle
= NEVER
;
1394 ast _ timer4_cycle
= NEVER
;
1396 switch (ast _ module_info
.type
) {
1397 case ASAP_TYPE_SAP_B
:
1398 call_6502_init(ast
, ast _ module_info
.init
, song
, 0, 0);
1400 case ASAP_TYPE_SAP_C
:
1401 #ifndef ASAP_ONLY_SAP
1407 call_6502_init(ast
, ast _ module_info
.player
+ 3, 0x70, ast _ module_info
.music
, ast _ module_info
.music
>> 8);
1408 call_6502_init(ast
, ast _ module_info
.player
+ 3, 0x00, song
, 0);
1410 case ASAP_TYPE_SAP_D
:
1411 case ASAP_TYPE_SAP_S
:
1416 ast _ cpu_pc
= ast _ module_info
.init
;
1418 #ifndef ASAP_ONLY_SAP
1420 call_6502_init(ast
, ast _ module_info
.player
+ 0x100, 0x00, 0x00, ast _ module_info
.song_pos
[song
]);
1423 call_6502_init(ast
, ast _ module_info
.player
, 0x00, ast _ module_info
.music
>> 8, ast _ module_info
.music
);
1424 call_6502_init(ast
, ast _ module_info
.player
, 0x02, ast _ module_info
.song_pos
[song
], 0);
1427 call_6502_init(ast
, ast _ module_info
.player
, ast _ module_info
.song_pos
[song
], ast _ module_info
.music
, ast _ module_info
.music
>> 8);
1431 call_6502_init(ast
, ast _ module_info
.player
, 0x70, ast _ module_info
.music
>> 8, ast _ module_info
.music
);
1432 call_6502_init(ast
, ast _ module_info
.player
, 0x00, song
, 0);
1433 ast _ tmc_per_frame_counter
= 1;
1437 ASAP_MutePokeyChannels(ast
, 0);
1440 FUNC(void, ASAP_MutePokeyChannels
, (P(ASAP_State PTR
, ast
), P(int, mask
)))
1442 PokeySound_Mute(ast
, ADDRESSOF ast _ base_pokey
, mask
);
1443 PokeySound_Mute(ast
, ADDRESSOF ast _ extra_pokey
, mask
>> 4);
1446 FUNC(abool
, call_6502_player
, (P(ASAP_State PTR
, ast
)))
1448 V(int, player
) = ast _ module_info
.player
;
1449 PokeySound_StartFrame(ast
);
1450 switch (ast _ module_info
.type
) {
1451 case ASAP_TYPE_SAP_B
:
1452 call_6502(ast
, player
, ast _ module_info
.fastplay
);
1454 case ASAP_TYPE_SAP_C
:
1455 #ifndef ASAP_ONLY_SAP
1461 call_6502(ast
, player
+ 6, ast _ module_info
.fastplay
);
1463 case ASAP_TYPE_SAP_D
:
1465 V(int, s
)= ast _ cpu_s
;
1466 #define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff
1467 #define RETURN_FROM_PLAYER_ADDR 0xd200
1468 /* save 6502 state on 6502 stack */
1469 PUSH_ON_6502_STACK(ast _ cpu_pc
>> 8);
1470 PUSH_ON_6502_STACK(ast _ cpu_pc
& 0xff);
1471 PUSH_ON_6502_STACK(((ast _ cpu_nz
| (ast _ cpu_nz
>> 1)) & 0x80) + ast _ cpu_vdi
+ \
1472 ((ast _ cpu_nz
& 0xff) == 0 ? Z_FLAG
: 0) + ast _ cpu_c
+ 0x20);
1473 PUSH_ON_6502_STACK(ast _ cpu_a
);
1474 PUSH_ON_6502_STACK(ast _ cpu_x
);
1475 PUSH_ON_6502_STACK(ast _ cpu_y
);
1476 /* RTS will jump to 6502 code that restores the state */
1477 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) >> 8);
1478 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR
- 1) & 0xff);
1480 dPutByte(RETURN_FROM_PLAYER_ADDR
, 0x68); /* PLA */
1481 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 1, 0xa8); /* TAY */
1482 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 2, 0x68); /* PLA */
1483 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 3, 0xaa); /* TAX */
1484 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 4, 0x68); /* PLA */
1485 dPutByte(RETURN_FROM_PLAYER_ADDR
+ 5, 0x40); /* RTI */
1486 ast _ cpu_pc
= player
;
1488 Cpu_RunScanlines(ast
, ast _ module_info
.fastplay
);
1490 case ASAP_TYPE_SAP_S
:
1491 Cpu_RunScanlines(ast
, ast _ module_info
.fastplay
);
1493 V(int, i
) = dGetByte(0x45) - 1;
1496 dPutByte(0xb07b, dGetByte(0xb07b) + 1);
1499 #ifndef ASAP_ONLY_SAP
1501 call_6502(ast
, player
+ 0x103, ast _ module_info
.fastplay
);
1506 call_6502(ast
, player
+ 3, ast _ module_info
.fastplay
);
1509 if (--ast _ tmc_per_frame_counter
<= 0) {
1510 ast _ tmc_per_frame_counter
= ast _ tmc_per_frame
;
1511 call_6502(ast
, player
+ 3, ast _ module_info
.fastplay
);
1514 call_6502(ast
, player
+ 6, ast _ module_info
.fastplay
);
1518 PokeySound_EndFrame(ast
, ast _ module_info
.fastplay
* 114);
1519 if (ast _ silence_cycles
> 0) {
1520 if (PokeySound_IsSilent(ADDRESSOF ast _ base_pokey
)
1521 && PokeySound_IsSilent(ADDRESSOF ast _ extra_pokey
)) {
1522 ast _ silence_cycles_counter
-= ast _ module_info
.fastplay
* 114;
1523 if (ast _ silence_cycles_counter
<= 0)
1527 ast _ silence_cycles_counter
= ast _ silence_cycles
;
1532 FUNC(int, ASAP_GetPosition
, (P(CONST ASAP_State PTR
, ast
)))
1534 return ast _ blocks_played
* 10 / (ASAP_SAMPLE_RATE
/ 100);
1537 FUNC(int, milliseconds_to_blocks
, (P(int, milliseconds
)))
1539 return milliseconds
* (ASAP_SAMPLE_RATE
/ 100) / 10;
1542 #ifndef ACTIONSCRIPT
1544 FUNC(void, ASAP_Seek
, (P(ASAP_State PTR
, ast
), P(int, position
)))
1546 V(int, block
) = milliseconds_to_blocks(position
);
1547 if (block
< ast _ blocks_played
)
1548 ASAP_PlaySong(ast
, ast _ current_song
, ast _ current_duration
);
1549 while (ast _ blocks_played
+ ast _ samples
- ast _ sample_index
< block
) {
1550 ast _ blocks_played
+= ast _ samples
- ast _ sample_index
;
1551 call_6502_player(ast
);
1553 ast _ sample_index
+= block
- ast _ blocks_played
;
1554 ast _ blocks_played
= block
;
1557 PRIVATE
FUNC(void, serialize_int
, (P(BYTEARRAY
, buffer
), P(int, offset
), P(int, value
)))
1559 buffer
[offset
] = TO_BYTE(value
);
1560 buffer
[offset
+ 1] = TO_BYTE(value
>> 8);
1561 buffer
[offset
+ 2] = TO_BYTE(value
>> 16);
1562 buffer
[offset
+ 3] = TO_BYTE(value
>> 24);
1565 FUNC(void, ASAP_GetWavHeaderForPart
, (
1566 P(CONST ASAP_State PTR
, ast
), P(BYTEARRAY
, buffer
),
1567 P(ASAP_SampleFormat
, format
), P(int, blocks
)))
1569 V(int, use_16bit
) = format
!= ASAP_FORMAT_U8
? 1 : 0;
1570 V(int, block_size
) = ast _ module_info
.channels
<< use_16bit
;
1571 V(int, bytes_per_second
) = ASAP_SAMPLE_RATE
* block_size
;
1572 V(int, remaining_blocks
) = milliseconds_to_blocks(ast _ current_duration
) - ast _ blocks_played
;
1574 if (blocks
> remaining_blocks
)
1575 blocks
= remaining_blocks
;
1576 n_bytes
= blocks
* block_size
;
1577 buffer
[0] = CAST(byte
) CHARCODE('R');
1578 buffer
[1] = CAST(byte
) CHARCODE('I');
1579 buffer
[2] = CAST(byte
) CHARCODE('F');
1580 buffer
[3] = CAST(byte
) CHARCODE('F');
1581 serialize_int(buffer
, 4, n_bytes
+ 36);
1582 buffer
[8] = CAST(byte
) CHARCODE('W');
1583 buffer
[9] = CAST(byte
) CHARCODE('A');
1584 buffer
[10] = CAST(byte
) CHARCODE('V');
1585 buffer
[11] = CAST(byte
) CHARCODE('E');
1586 buffer
[12] = CAST(byte
) CHARCODE('f');
1587 buffer
[13] = CAST(byte
) CHARCODE('m');
1588 buffer
[14] = CAST(byte
) CHARCODE('t');
1589 buffer
[15] = CAST(byte
) CHARCODE(' ');
1596 buffer
[22] = CAST(byte
) ast _ module_info
.channels
;
1598 serialize_int(buffer
, 24, ASAP_SAMPLE_RATE
);
1599 serialize_int(buffer
, 28, bytes_per_second
);
1600 buffer
[32] = CAST(byte
) block_size
;
1602 buffer
[34] = CAST(byte
) (8 << use_16bit
);
1604 buffer
[36] = CAST(byte
) CHARCODE('d');
1605 buffer
[37] = CAST(byte
) CHARCODE('a');
1606 buffer
[38] = CAST(byte
) CHARCODE('t');
1607 buffer
[39] = CAST(byte
) CHARCODE('a');
1608 serialize_int(buffer
, 40, n_bytes
);
1611 FUNC(void, ASAP_GetWavHeader
, (
1612 P(CONST ASAP_State PTR
, ast
), P(BYTEARRAY
, buffer
), P(ASAP_SampleFormat
, format
)))
1614 V(int, remaining_blocks
) = milliseconds_to_blocks(ast _ current_duration
) - ast _ blocks_played
;
1615 ASAP_GetWavHeaderForPart(ast
, buffer
, format
, remaining_blocks
);
1618 #endif /* ACTIONSCRIPT */
1620 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
)))
1622 V(int, block_shift
);
1623 V(int, buffer_blocks
);
1625 if (ast _ silence_cycles
> 0 && ast _ silence_cycles_counter
<= 0)
1630 block_shift
= (ast _ module_info
.channels
- 1) + (format
!= ASAP_FORMAT_U8
? 1 : 0);
1632 buffer_blocks
= buffer_len
>> block_shift
;
1633 if (ast _ current_duration
> 0) {
1634 V(int, total_blocks
) = milliseconds_to_blocks(ast _ current_duration
);
1635 if (buffer_blocks
> total_blocks
- ast _ blocks_played
)
1636 buffer_blocks
= total_blocks
- ast _ blocks_played
;
1640 V(int, blocks
) = PokeySound_Generate(ast
, CAST(BYTEARRAY
) buffer
,
1641 buffer_offset
+ (block
<< block_shift
), buffer_blocks
- block
, format
);
1642 ast _ blocks_played
+= blocks
;
1644 } while (block
< buffer_blocks
&& call_6502_player(ast
));
1645 return block
<< block_shift
;
1648 FUNC(int, ASAP_Generate
, (P(ASAP_State PTR
, ast
), P(VOIDPTR
, buffer
), P(int, buffer_len
), P(ASAP_SampleFormat
, format
)))
1650 return ASAP_GenerateAt(ast
, buffer
, 0, buffer_len
, format
);
1653 #if defined(C) && !defined(ASAP_ONLY_SAP)
1655 abool
ASAP_ChangeExt(char *filename
, const char *ext
)
1658 while (*filename
!= '\0') {
1659 if (*filename
== '/' || *filename
== '\\')
1661 else if (*filename
== '.')
1662 dest
= filename
+ 1;
1671 abool
ASAP_CanSetModuleInfo(const char *filename
)
1673 int ext
= get_packed_ext(filename
);
1674 return ext
== ASAP_EXT('S', 'A', 'P');
1677 static byte
*put_string(byte
*dest
, const char *str
)
1679 while (*str
!= '\0')
1684 static byte
*put_dec(byte
*dest
, int value
)
1687 dest
= put_dec(dest
, value
/ 10);
1690 *dest
++ = '0' + value
;
1694 static byte
*put_text_tag(byte
*dest
, const char *tag
, const char *value
)
1696 dest
= put_string(dest
, tag
);
1700 while (*value
!= '\0') {
1701 if (*value
< ' ' || *value
> 'z' || *value
== '"' || *value
== '`')
1711 static byte
*put_dec_tag(byte
*dest
, const char *tag
, int value
)
1713 dest
= put_string(dest
, tag
);
1714 dest
= put_dec(dest
, value
);
1720 static byte
*put_hex_tag(byte
*dest
, const char *tag
, int value
)
1725 dest
= put_string(dest
, tag
);
1726 for (i
= 12; i
>= 0; i
-= 4) {
1727 int digit
= (value
>> i
) & 0xf;
1728 *dest
++ = (byte
) (digit
+ (digit
< 10 ? '0' : 'A' - 10));
1735 static byte
*start_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1737 dest
= put_string(dest
, "SAP\r\n");
1738 dest
= put_text_tag(dest
, "AUTHOR ", module_info
->author
);
1741 dest
= put_text_tag(dest
, "NAME ", module_info
->name
);
1744 dest
= put_text_tag(dest
, "DATE ", module_info
->date
);
1747 if (module_info
->songs
> 1) {
1748 dest
= put_dec_tag(dest
, "SONGS ", module_info
->songs
);
1749 if (module_info
->default_song
> 0)
1750 dest
= put_dec_tag(dest
, "DEFSONG ", module_info
->default_song
);
1752 if (module_info
->channels
> 1)
1753 dest
= put_string(dest
, "STEREO\r\n");
1757 static char *two_digits(char *s
, int x
)
1759 s
[0] = '0' + x
/ 10;
1760 s
[1] = '0' + x
% 10;
1764 void ASAP_DurationToString(char *s
, int duration
)
1766 if (duration
>= 0 && duration
< 100 * 60 * 1000) {
1767 int seconds
= duration
/ 1000;
1768 s
= two_digits(s
, seconds
/ 60);
1770 s
= two_digits(s
, seconds
% 60);
1772 if (duration
!= 0) {
1774 s
= two_digits(s
, duration
/ 10);
1777 *s
++ = '0' + duration
;
1783 static byte
*put_durations(byte
*dest
, const ASAP_ModuleInfo
*module_info
)
1786 for (song
= 0; song
< module_info
->songs
; song
++) {
1787 if (module_info
->durations
[song
] < 0)
1789 dest
= put_string(dest
, "TIME ");
1790 ASAP_DurationToString((char *) dest
, module_info
->durations
[song
]);
1791 while (*dest
!= '\0')
1793 if (module_info
->loops
[song
])
1794 dest
= put_string(dest
, " LOOP");
1801 static byte
*put_sap_header(byte
*dest
, const ASAP_ModuleInfo
*module_info
, char type
, int music
, int init
, int player
)
1803 dest
= start_sap_header(dest
, module_info
);
1806 dest
= put_string(dest
, "TYPE ");
1810 if (module_info
->fastplay
!= 312)
1811 dest
= put_dec_tag(dest
, "FASTPLAY ", module_info
->fastplay
);
1812 dest
= put_hex_tag(dest
, "MUSIC ", music
);
1813 dest
= put_hex_tag(dest
, "INIT ", init
);
1814 dest
= put_hex_tag(dest
, "PLAYER ", player
);
1815 dest
= put_durations(dest
, module_info
);
1819 int ASAP_SetModuleInfo(const ASAP_ModuleInfo
*module_info
, const BYTEARRAY module
, int module_len
, BYTEARRAY out_module
)
1823 if (memcmp(module
, "SAP\r\n", 5) != 0)
1825 dest
= start_sap_header(out_module
, module_info
);
1829 while (i
< module_len
&& module
[i
] != 0xff) {
1830 if (memcmp(module
+ i
, "AUTHOR ", 7) == 0
1831 || memcmp(module
+ i
, "NAME ", 5) == 0
1832 || memcmp(module
+ i
, "DATE ", 5) == 0
1833 || memcmp(module
+ i
, "SONGS ", 6) == 0
1834 || memcmp(module
+ i
, "DEFSONG ", 8) == 0
1835 || memcmp(module
+ i
, "STEREO\r", 7) == 0
1836 || memcmp(module
+ i
, "TIME ", 5) == 0) {
1837 while (i
< module_len
&& module
[i
++] != 0x0a);
1844 } while (i
< module_len
&& b
!= 0x0a);
1847 dest
= put_durations(dest
, module_info
);
1849 memcpy(dest
, module
+ i
, module_len
);
1851 return dest
- out_module
;
1854 #define RMT_INIT 0x0c80
1855 #define TM2_INIT 0x1080
1857 const char *ASAP_CanConvert(
1858 const char *filename
, const ASAP_ModuleInfo
*module_info
,
1859 const BYTEARRAY module
, int module_len
)
1862 switch (module_info
->type
) {
1863 case ASAP_TYPE_SAP_B
:
1864 if ((module_info
->init
== 0x3fb || module_info
->init
== 0x3f9) && module_info
->player
== 0x503)
1866 if (module_info
->init
== 0x4f3 || module_info
->init
== 0xf4f3 || module_info
->init
== 0x4ef)
1867 return module_info
->fastplay
== 156 ? "mpd" : "mpt";
1868 if (module_info
->init
== RMT_INIT
)
1870 if ((module_info
->init
== 0x4f5 || module_info
->init
== 0xf4f5 || module_info
->init
== 0x4f2)
1871 || ((module_info
->init
== 0x4e7 || module_info
->init
== 0xf4e7 || module_info
->init
== 0x4e4) && module_info
->fastplay
== 156)
1872 || ((module_info
->init
== 0x4e5 || module_info
->init
== 0xf4e5 || module_info
->init
== 0x4e2) && (module_info
->fastplay
== 104 || module_info
->fastplay
== 78)))
1874 if (module_info
->init
== TM2_INIT
)
1877 case ASAP_TYPE_SAP_C
:
1878 if (module_info
->player
== 0x500 || module_info
->player
== 0xf500) {
1879 if (module_info
->fastplay
== 156)
1881 if (module_info
->channels
> 1)
1883 if (module
[module_len
- 170] == 0x1e)
1885 if (module
[module_len
- 909] == 0x30)
1907 const char *filename
, const ASAP_ModuleInfo
*module_info
,
1908 const BYTEARRAY module
, int module_len
, BYTEARRAY out_module
)
1915 static const int tmc_player
[4] = { 3, -9, -10, -10 };
1916 static const int tmc_init
[4] = { -14, -16, -17, -17 };
1917 switch (module_info
->type
) {
1918 case ASAP_TYPE_SAP_B
:
1919 case ASAP_TYPE_SAP_C
:
1920 out_len
= UWORD(module
, module_info
->header_len
+ 4) - UWORD(module
, module_info
->header_len
+ 2) + 7;
1921 if (out_len
< 7 || module_info
->header_len
+ out_len
>= module_len
)
1923 memcpy(out_module
, module
+ module_info
->header_len
, out_len
);
1929 dest
= put_sap_header(out_module
, module_info
, 'C', module_info
->music
, -1, module_info
->player
);
1932 memcpy(dest
, module
, module_len
);
1933 dest
[0] = 0xff; /* some modules start with zeros */
1936 if (module_info
->type
== ASAP_TYPE_CM3
) {
1937 memcpy(dest
, cm3_obx
+ 2, sizeof(cm3_obx
) - 2);
1938 dest
+= sizeof(cm3_obx
) - 2;
1940 else if (module_info
->type
== ASAP_TYPE_CMS
) {
1941 memcpy(dest
, cms_obx
+ 2, sizeof(cms_obx
) - 2);
1942 dest
+= sizeof(cms_obx
) - 2;
1945 memcpy(dest
, cmc_obx
+ 2, sizeof(cmc_obx
) - 2);
1946 if (module_info
->type
== ASAP_TYPE_CMR
)
1947 memcpy(dest
+ 4 + CMR_BASS_TABLE_OFFSET
, cmr_bass_table
, sizeof(cmr_bass_table
));
1948 dest
+= sizeof(cmc_obx
) - 2;
1950 return dest
- out_module
;
1952 if (module_info
->songs
!= 1) {
1953 addr
= module_info
->player
- 7 - module_info
->songs
;
1954 dest
= put_sap_header(out_module
, module_info
, 'B', -1, module_info
->player
- 7, module_info
->player
+ 0x103);
1957 addr
= module_info
->player
- 5;
1958 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, module_info
->player
+ 0x103);
1962 memcpy(dest
, module
, module_len
);
1963 if (module_len
== 0x2c06) {
1969 *dest
++ = (byte
) addr
;
1970 *dest
++ = (byte
) (addr
>> 8);
1971 *dest
++ = dlt_obx
[4];
1972 *dest
++ = dlt_obx
[5];
1973 if (module_info
->songs
!= 1) {
1974 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
1975 dest
+= module_info
->songs
;
1976 *dest
++ = 0xaa; /* tax */
1977 *dest
++ = 0xbc; /* ldy song2pos,x */
1978 *dest
++ = (byte
) addr
;
1979 *dest
++ = (byte
) (addr
>> 8);
1982 *dest
++ = 0xa0; /* ldy #0 */
1985 *dest
++ = 0x4c; /* jmp init */
1986 *dest
++ = (byte
) module_info
->player
;
1987 *dest
++ = (byte
) ((module_info
->player
>> 8) + 1);
1988 memcpy(dest
, dlt_obx
+ 6, sizeof(dlt_obx
) - 6);
1989 dest
+= sizeof(dlt_obx
) - 6;
1990 return dest
- out_module
;
1992 if (module_info
->songs
!= 1) {
1993 addr
= module_info
->player
- 17 - module_info
->songs
;
1994 dest
= put_sap_header(out_module
, module_info
, 'B', -1, module_info
->player
- 17, module_info
->player
+ 3);
1997 addr
= module_info
->player
- 13;
1998 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, module_info
->player
+ 3);
2002 memcpy(dest
, module
, module_len
);
2004 *dest
++ = (byte
) addr
;
2005 *dest
++ = (byte
) (addr
>> 8);
2006 *dest
++ = mpt_obx
[4];
2007 *dest
++ = mpt_obx
[5];
2008 if (module_info
->songs
!= 1) {
2009 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
2010 dest
+= module_info
->songs
;
2011 *dest
++ = 0x48; /* pha */
2013 *dest
++ = 0xa0; /* ldy #<music */
2014 *dest
++ = (byte
) module_info
->music
;
2015 *dest
++ = 0xa2; /* ldx #>music */
2016 *dest
++ = (byte
) (module_info
->music
>> 8);
2017 *dest
++ = 0xa9; /* lda #0 */
2019 *dest
++ = 0x20; /* jsr player */
2020 *dest
++ = (byte
) module_info
->player
;
2021 *dest
++ = (byte
) (module_info
->player
>> 8);
2022 if (module_info
->songs
!= 1) {
2023 *dest
++ = 0x68; /* pla */
2024 *dest
++ = 0xa8; /* tay */
2025 *dest
++ = 0xbe; /* ldx song2pos,y */
2026 *dest
++ = (byte
) addr
;
2027 *dest
++ = (byte
) (addr
>> 8);
2030 *dest
++ = 0xa2; /* ldx #0 */
2033 *dest
++ = 0xa9; /* lda #2 */
2035 memcpy(dest
, mpt_obx
+ 6, sizeof(mpt_obx
) - 6);
2036 dest
+= sizeof(mpt_obx
) - 6;
2037 return dest
- out_module
;
2039 dest
= put_sap_header(out_module
, module_info
, 'B', -1, RMT_INIT
, module_info
->player
+ 3);
2042 memcpy(dest
, module
, module_len
);
2044 *dest
++ = (byte
) RMT_INIT
;
2045 *dest
++ = (byte
) (RMT_INIT
>> 8);
2046 if (module_info
->songs
!= 1) {
2047 addr
= RMT_INIT
+ 10 + module_info
->songs
;
2048 *dest
++ = (byte
) addr
;
2049 *dest
++ = (byte
) (addr
>> 8);
2050 *dest
++ = 0xa8; /* tay */
2051 *dest
++ = 0xb9; /* lda song2pos,y */
2052 *dest
++ = (byte
) (RMT_INIT
+ 11);
2053 *dest
++ = (byte
) ((RMT_INIT
+ 11) >> 8);
2056 *dest
++ = (byte
) (RMT_INIT
+ 8);
2057 *dest
++ = (byte
) ((RMT_INIT
+ 8) >> 8);
2058 *dest
++ = 0xa9; /* lda #0 */
2061 *dest
++ = 0xa2; /* ldx #<music */
2062 *dest
++ = (byte
) module_info
->music
;
2063 *dest
++ = 0xa0; /* ldy #>music */
2064 *dest
++ = (byte
) (module_info
->music
>> 8);
2065 *dest
++ = 0x4c; /* jmp player */
2066 *dest
++ = (byte
) module_info
->player
;
2067 *dest
++ = (byte
) (module_info
->player
>> 8);
2068 if (module_info
->songs
!= 1) {
2069 memcpy(dest
, module_info
->song_pos
, module_info
->songs
);
2070 dest
+= module_info
->songs
;
2072 if (module_info
->channels
== 1) {
2073 memcpy(dest
, rmt4_obx
+ 2, sizeof(rmt4_obx
) - 2);
2074 dest
+= sizeof(rmt4_obx
) - 2;
2077 memcpy(dest
, rmt8_obx
+ 2, sizeof(rmt8_obx
) - 2);
2078 dest
+= sizeof(rmt8_obx
) - 2;
2080 return dest
- out_module
;
2082 player
= module_info
->player
+ tmc_player
[module
[0x25] - 1];
2083 addr
= player
+ tmc_init
[module
[0x25] - 1];
2084 if (module_info
->songs
!= 1)
2086 dest
= put_sap_header(out_module
, module_info
, 'B', -1, addr
, player
);
2089 memcpy(dest
, module
, module_len
);
2091 *dest
++ = (byte
) addr
;
2092 *dest
++ = (byte
) (addr
>> 8);
2093 *dest
++ = tmc_obx
[4];
2094 *dest
++ = tmc_obx
[5];
2095 if (module_info
->songs
!= 1)
2096 *dest
++ = 0x48; /* pha */
2097 *dest
++ = 0xa0; /* ldy #<music */
2098 *dest
++ = (byte
) module_info
->music
;
2099 *dest
++ = 0xa2; /* ldx #>music */
2100 *dest
++ = (byte
) (module_info
->music
>> 8);
2101 *dest
++ = 0xa9; /* lda #$70 */
2103 *dest
++ = 0x20; /* jsr player */
2104 *dest
++ = (byte
) module_info
->player
;
2105 *dest
++ = (byte
) (module_info
->player
>> 8);
2106 if (module_info
->songs
!= 1) {
2107 *dest
++ = 0x68; /* pla */
2108 *dest
++ = 0xaa; /* tax */
2109 *dest
++ = 0xa9; /* lda #0 */
2113 *dest
++ = 0xa9; /* lda #$60 */
2116 switch (module
[0x25]) {
2118 *dest
++ = 0x06; /* asl 0 */
2120 *dest
++ = 0x4c; /* jmp player */
2121 *dest
++ = (byte
) module_info
->player
;
2122 *dest
++ = (byte
) (module_info
->player
>> 8);
2123 *dest
++ = 0xa5; /* lda 0 */
2125 *dest
++ = 0xe6; /* inc 0 */
2127 *dest
++ = 0x4a; /* lsr @ */
2128 *dest
++ = 0x90; /* bcc player+3 */
2130 *dest
++ = 0xb0; /* bcs player+6 */
2135 *dest
++ = 0xa0; /* ldy #1 */
2137 *dest
++ = 0x84; /* sty 0 */
2139 *dest
++ = 0xd0; /* bne player */
2141 *dest
++ = 0xc6; /* dec 0 */
2143 *dest
++ = 0xd0; /* bne player+6 */
2145 *dest
++ = 0xa0; /* ldy #3 */
2146 *dest
++ = module
[0x25];
2147 *dest
++ = 0x84; /* sty 0 */
2149 *dest
++ = 0xd0; /* bne player+3 */
2155 memcpy(dest
, tmc_obx
+ 6, sizeof(tmc_obx
) - 6);
2156 dest
+= sizeof(tmc_obx
) - 6;
2157 return dest
- out_module
;
2159 dest
= put_sap_header(out_module
, module_info
, 'B', -1, TM2_INIT
, module_info
->player
+ 3);
2162 memcpy(dest
, module
, module_len
);
2164 *dest
++ = (byte
) TM2_INIT
;
2165 *dest
++ = (byte
) (TM2_INIT
>> 8);
2166 if (module_info
->songs
!= 1) {
2167 *dest
++ = (byte
) (TM2_INIT
+ 16);
2168 *dest
++ = (byte
) ((TM2_INIT
+ 16) >> 8);
2169 *dest
++ = 0x48; /* pha */
2172 *dest
++ = (byte
) (TM2_INIT
+ 14);
2173 *dest
++ = (byte
) ((TM2_INIT
+ 14) >> 8);
2175 *dest
++ = 0xa0; /* ldy #<music */
2176 *dest
++ = (byte
) module_info
->music
;
2177 *dest
++ = 0xa2; /* ldx #>music */
2178 *dest
++ = (byte
) (module_info
->music
>> 8);
2179 *dest
++ = 0xa9; /* lda #$70 */
2181 *dest
++ = 0x20; /* jsr player */
2182 *dest
++ = (byte
) module_info
->player
;
2183 *dest
++ = (byte
) (module_info
->player
>> 8);
2184 if (module_info
->songs
!= 1) {
2185 *dest
++ = 0x68; /* pla */
2186 *dest
++ = 0xaa; /* tax */
2187 *dest
++ = 0xa9; /* lda #0 */
2191 *dest
++ = 0xa9; /* lda #0 */
2193 *dest
++ = 0xaa; /* tax */
2195 *dest
++ = 0x4c; /* jmp player */
2196 *dest
++ = (byte
) module_info
->player
;
2197 *dest
++ = (byte
) (module_info
->player
>> 8);
2198 memcpy(dest
, tm2_obx
+ 2, sizeof(tm2_obx
) - 2);
2199 dest
+= sizeof(tm2_obx
) - 2;
2200 return dest
- out_module
;
2206 #endif /* defined(C) && !defined(ASAP_ONLY_SAP) */