Submit initial patch from FS#12176. Adds support for several new game music formats...
[kugel-rb.git] / apps / codecs / libasap / asap.c
blob1aeb843fa37c188158c743b7851a6331cf6bb098
1 /*
2 * asap.c - ASAP engine
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;
29 #ifdef ASAP_ONLY_INFO
31 #define GET_PLAYER(name) NULL
33 #else
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) {
40 case 0xd014:
41 return ast _ module_info->ntsc ? 0xf : 1;
42 case 0xd20a:
43 case 0xd21a:
44 return PokeySound_GetRandom(ast, addr, ast _ cycle);
45 case 0xd20e:
46 return ast _ irqst;
47 case 0xd21e:
48 if (ast _ extra_pokey_mask != 0) {
49 /* interrupts in the extra POKEY not emulated at the moment */
50 return 0xff;
52 return ast _ irqst;
53 case 0xd20c:
54 case 0xd21c:
55 case 0xd20f: /* just because some SAP files rely on this */
56 case 0xd21f:
57 return 0xff;
58 case 0xd40b:
59 case 0xd41b:
60 return ast _ scanline_number >> 1;
61 default:
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; \
80 } \
81 } \
82 else \
83 ast _ timer##ch##_cycle = NEVER;
84 SET_TIMER_IRQ(1);
85 SET_TIMER_IRQ(2);
86 SET_TIMER_IRQ(4);
88 else
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;
94 else
95 ast _ cycle = ast _ next_scanline_cycle + 106;
97 else if ((addr & 0xff00) == ast _ module_info->covox_addr) {
98 V(PokeyState PTR, pst);
99 addr &= 3;
100 if (addr == 0 || addr == 3)
101 pst = ADDRESSOF ast _ base_pokey;
102 else
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);
109 V(int, delta);
110 data &= 8;
111 /* NOT data - ast _ consol; reverse to the POKEY sound */
112 delta = (ast _ consol - data) << DELTA_SHIFT_GTIA;
113 ast _ consol = data;
114 ast _ base_pokey.delta_buffer[sample] += delta;
115 ast _ extra_pokey.delta_buffer[sample] += delta;
117 else
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
129 #ifndef JAVA
130 #include "players.h"
131 #endif
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
141 END_CONST_ARRAY;
143 #endif /* ASAP_ONLY_INFO */
145 CONST_ARRAY(int, perframe2fastplay)
146 312, 312 / 2, 312 / 3, 312 / 4
147 END_CONST_ARRAY;
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);
156 #endif
157 V(int, music_last_byte);
158 V(int, block_len);
159 if ((UBYTE(module[0]) != 0xff || UBYTE(module[1]) != 0xff)
160 && (module[0] != 0 || module[1] != 0)) /* some CMC and clones start with zeros */
161 return FALSE;
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)
167 return FALSE;
168 #endif
169 music_last_byte = UWORD(module, 4);
170 if (module_info _ music <= 0xd7ff && music_last_byte >= 0xd000)
171 return FALSE;
172 block_len = music_last_byte + 1 - module_info _ music;
173 if (6 + block_len != module_len) {
174 V(int, info_addr);
175 V(int, info_len);
176 if (module_info _ type != ASAP_TYPE_RMT || 11 + block_len > module_len)
177 return FALSE;
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)
181 return FALSE;
182 info_len = UWORD(module, 8 + block_len) + 1 - info_addr;
183 if (10 + block_len + info_len != module_len)
184 return FALSE;
186 #ifndef ASAP_ONLY_INFO
187 if (ast != NULL) {
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);
191 #endif
192 return TRUE;
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);
213 INIT_ARRAY(seen);
214 while (pos >= 0 && pos < 0x55) {
215 V(int, p1);
216 V(int, p2);
217 V(int, p3);
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)
221 seen[p1] = 0;
222 rep_times--;
223 pos = rep_start_pos;
225 if (seen[pos] != 0) {
226 if (seen[pos] != SEEN_THIS_CALL)
227 module_info _ loops[module_info _ songs] = TRUE;
228 break;
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) {
235 pos++;
236 continue;
238 p1 >>= 4;
239 if (p1 == 8)
240 break;
241 if (p1 == 9) {
242 pos = p2;
243 continue;
245 if (p1 == 0xa) {
246 pos -= p2;
247 continue;
249 if (p1 == 0xb) {
250 pos += p2;
251 continue;
253 if (p1 == 0xc) {
254 tempo = p2;
255 pos++;
256 continue;
258 if (p1 == 0xd) {
259 pos++;
260 rep_start_pos = pos;
261 rep_end_pos = pos + p2;
262 rep_times = p3 - 1;
263 continue;
265 if (p1 == 0xe) {
266 module_info _ loops[module_info _ songs] = TRUE;
267 break;
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);
274 pos++;
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)))
283 V(int, last_pos);
284 V(int, pos);
285 if (module_len < 0x306)
286 return FALSE;
287 module_info _ type = type;
288 if (!load_native(ast, module_info, module, module_len, player))
289 return FALSE;
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));
293 #endif
294 last_pos = 0x54;
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)
299 break;
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)
304 break;
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);
312 return TRUE;
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)))
325 V(int, ch);
326 for (ch = 0; ch < 4; ch++) {
327 V(int, pattern) = UBYTE(module[0x2006 + (ch << 8) + pos]);
328 if (pattern < 64) {
329 V(int, offset) = 6 + (pattern << 7) + (i << 1);
330 if ((module[offset] & 0x80) == 0 && (module[offset + 1] & 0x80) != 0)
331 return TRUE;
334 return FALSE;
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;
343 V(int, tempo) = 6;
344 while (pos < 128 && !seen[pos] && is_dlt_track_empty(module, pos))
345 seen[pos++] = TRUE;
346 module_info _ song_pos[module_info _ songs] = CAST(byte) pos;
347 while (pos < 128) {
348 V(int, p1);
349 if (seen[pos]) {
350 loop = TRUE;
351 break;
353 seen[pos] = TRUE;
354 p1 = module[0x2006 + pos];
355 if (p1 == 0x40 || is_dlt_track_empty(module, pos))
356 break;
357 if (p1 == 0x41)
358 pos = UBYTE(module[0x2086 + pos]);
359 else if (p1 == 0x42)
360 tempo = UBYTE(module[0x2086 + pos++]);
361 else {
362 V(int, i);
363 for (i = 0; i < 64 && !is_dlt_pattern_end(module, pos, i); i++)
364 player_calls += tempo;
365 pos++;
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)))
378 V(int, pos);
379 NEW_ARRAY(abool, seen, 128);
380 if (module_len == 0x2c06) {
381 if (ast != NULL)
382 ast _ memory[0x4c00] = 0;
384 else if (module_len != 0x2c07)
385 return FALSE;
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) {
389 return FALSE;
391 INIT_ARRAY(seen);
392 module_info _ songs = 0;
393 for (pos = 0; pos < 128 && module_info _ songs < ASAP_SONGS_MAX; pos++) {
394 if (!seen[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);
411 INIT_ARRAY(seen);
412 INIT_ARRAY(blank_rows);
413 while (pos < song_len) {
414 V(int, i);
415 V(int, ch);
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;
420 break;
422 seen[pos] = SEEN_THIS_CALL;
423 global_seen[pos] = TRUE;
424 i = UBYTE(module[0x1d0 + pos * 2]);
425 if (i == 0xff) {
426 pos = UBYTE(module[0x1d1 + pos * 2]);
427 continue;
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]);
432 if (i >= 0x40)
433 break;
434 i <<= 1;
435 i = UWORD(module, 0x46 + i);
436 pattern_offset[ch] = i == 0 ? 0 : i - addr_to_offset;
437 blank_rows_counter[ch] = 0;
439 if (ch >= 0)
440 break;
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)
447 continue;
448 for (;;) {
449 i = UBYTE(module[pattern_offset[ch]++]);
450 if (i < 0x40 || i == 0xfe)
451 break;
452 if (i < 0x80)
453 continue;
454 if (i < 0xc0) {
455 blank_rows[ch] = i - 0x80;
456 continue;
458 if (i < 0xd0)
459 continue;
460 if (i < 0xe0) {
461 tempo = i - 0xcf;
462 continue;
464 pattern_rows = 0;
466 blank_rows_counter[ch] = blank_rows[ch];
468 player_calls += tempo;
470 pos++;
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)))
480 V(int, track0_addr);
481 V(int, pos);
482 V(int, song_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)
486 return FALSE;
487 module_info _ type = ASAP_TYPE_MPT;
488 if (!load_native(ast, module_info, module, module_len, GET_PLAYER(mpt)))
489 return FALSE;
490 track0_addr = UWORD(module, 2) + 0x1ca;
491 if (UBYTE(module[0x1c6]) + (UBYTE(module[0x1ca]) << 8) != track0_addr)
492 return FALSE;
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;
497 if (song_len > 0xfe)
498 return FALSE;
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
512 END_CONST_ARRAY;
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];
520 V(int, player_call);
521 V(int, player_calls);
522 V(int, index);
523 V(int, index_end);
524 V(int, index_loop);
525 V(int, volume_slide_depth);
526 V(int, volume_min);
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)
531 return 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;
543 else {
544 do {
545 V(int, vol) = module[instrument + index];
546 if (extra_pokey)
547 vol >>= 4;
548 if ((vol & 0xf) >= rmt_volume_silent[volume])
549 player_calls = player_call + 1;
550 player_call++;
551 index += 3;
552 } while (index < index_end);
554 if (volume_slide_depth == 0)
555 return player_calls / per_frame;
556 volume_slide = 128;
557 silent_loop = FALSE;
558 for (;;) {
559 V(int, vol);
560 if (index >= index_end) {
561 if (silent_loop)
562 break;
563 silent_loop = TRUE;
564 index = index_loop;
566 vol = module[instrument + index];
567 if (extra_pokey)
568 vol >>= 4;
569 if ((vol & 0xf) >= rmt_volume_silent[volume]) {
570 player_calls = player_call + 1;
571 silent_loop = FALSE;
573 player_call++;
574 index += 3;
575 volume_slide -= volume_slide_depth;
576 if (volume_slide < 0) {
577 volume_slide += 256;
578 if (--volume <= volume_min)
579 break;
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)))
589 V(int, ch);
590 V(int, addr_to_offset) = UWORD(module, 2) - 6;
591 V(int, tempo) = UBYTE(module[0xb]);
592 V(int, frames) = 0;
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);
605 INIT_ARRAY(seen);
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) {
611 V(int, i);
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;
616 break;
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]);
622 continue;
624 for (ch = 0; ch < 1 << pos_shift; ch++) {
625 i = UBYTE(module[song_offset + (pos << pos_shift) + ch]);
626 if (i == 0xff)
627 blank_rows[ch] = 256;
628 else {
629 pattern_offset[ch] = pattern_begin[ch] = UBYTE(module[pattern_lo_offset + i])
630 + (UBYTE(module[pattern_hi_offset + i]) << 8) - addr_to_offset;
631 blank_rows[ch] = 0;
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)
640 continue;
641 for (;;) {
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;
651 break;
653 if (i == 62) {
654 blank_rows[ch] = UBYTE(module[pattern_offset[ch]++]);
655 break;
657 if ((i & 0x3f) == 62) {
658 blank_rows[ch] = i >> 6;
659 break;
661 if ((i & 0xbf) == 63) {
662 tempo = UBYTE(module[pattern_offset[ch]++]);
663 continue;
665 if (i == 0xbf) {
666 pattern_offset[ch] = pattern_begin[ch] + UBYTE(module[pattern_offset[ch]]);
667 continue;
669 /* assert(i == 0xff); */
670 pattern_rows = -1;
671 break;
673 if (pattern_rows < 0)
674 break;
676 if (pattern_rows >= 0)
677 frames += tempo;
679 pos++;
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;
693 if (frames > 0)
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)))
701 V(int, per_frame);
702 V(int, pos_shift);
703 V(int, song_len);
704 V(int, pos);
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)
708 return FALSE;
709 switch (CAST(char) module[9]) {
710 case CHARCODE('4'):
711 pos_shift = 2;
712 break;
713 case CHARCODE('8'):
714 module_info _ channels = 2;
715 pos_shift = 3;
716 break;
717 default:
718 return FALSE;
720 per_frame = module[0xc];
721 if (per_frame < 1 || per_frame > 4)
722 return FALSE;
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)))
726 return FALSE;
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)
730 song_len += 4;
731 song_len >>= pos_shift;
732 if (song_len >= 0x100)
733 return FALSE;
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;
753 V(int, frames) = 0;
754 NEW_ARRAY(int, pattern_offset, 8);
755 NEW_ARRAY(int, blank_rows, 8);
756 while (UBYTE(module[0x1a6 + 15 + pos]) < 0x80) {
757 V(int, ch);
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;
762 blank_rows[ch] = 0;
764 for (pattern_rows = 64; --pattern_rows >= 0; ) {
765 for (ch = 7; ch >= 0; ch--) {
766 if (--blank_rows[ch] >= 0)
767 continue;
768 for (;;) {
769 V(int, i) = UBYTE(module[pattern_offset[ch]++]);
770 if (i < 0x40) {
771 pattern_offset[ch]++;
772 break;
774 if (i == 0x40) {
775 i = UBYTE(module[pattern_offset[ch]++]);
776 if ((i & 0x7f) == 0)
777 pattern_rows = 0;
778 else
779 tempo = (i & 0x7f) + 1;
780 if (i >= 0x80)
781 pattern_offset[ch]++;
782 break;
784 if (i < 0x80) {
785 i = module[pattern_offset[ch]++] & 0x7f;
786 if (i == 0)
787 pattern_rows = 0;
788 else
789 tempo = i + 1;
790 pattern_offset[ch]++;
791 break;
793 if (i < 0xc0)
794 continue;
795 blank_rows[ch] = i - 0xbf;
796 break;
799 frames += tempo;
801 pos += 16;
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)))
812 V(int, i);
813 V(int, last_pos);
814 if (module_len < 0x1d0)
815 return FALSE;
816 module_info _ type = ASAP_TYPE_TMC;
817 if (!load_native(ast, module_info, module, module_len, GET_PLAYER(tmc)))
818 return FALSE;
819 module_info _ channels = 2;
820 i = 0;
821 /* find first instrument */
822 while (module[0x66 + i] == 0) {
823 if (++i >= 64)
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)
829 return FALSE;
830 /* skip trailing jumps */
831 do {
832 if (last_pos <= 0)
833 return FALSE; /* no pattern to play */
834 last_pos -= 16;
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 */
842 i = module[0x25];
843 if (i < 1 || i > 4)
844 return FALSE;
845 if (ast != NULL)
846 ast _ tmc_per_frame = module[0x25];
847 module_info _ fastplay = perframe2fastplay[i - 1];
848 return TRUE;
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);
859 for (;;) {
860 V(int, ch);
861 V(int, pattern_rows) = UBYTE(module[0x386 + 16 + pos]);
862 if (pattern_rows == 0)
863 break;
864 if (pattern_rows >= 0x80) {
865 module_info _ loops[module_info _ songs] = TRUE;
866 break;
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;
871 blank_rows[ch] = 0;
873 while (--pattern_rows >= 0) {
874 for (ch = 7; ch >= 0; ch--) {
875 if (--blank_rows[ch] >= 0)
876 continue;
877 for (;;) {
878 V(int, i) = UBYTE(module[pattern_offset[ch]++]);
879 if (i == 0) {
880 pattern_offset[ch]++;
881 break;
883 if (i < 0x40) {
884 if (UBYTE(module[pattern_offset[ch]++]) >= 0x80)
885 pattern_offset[ch]++;
886 break;
888 if (i < 0x80) {
889 pattern_offset[ch]++;
890 break;
892 if (i == 0x80) {
893 blank_rows[ch] = UBYTE(module[pattern_offset[ch]++]);
894 break;
896 if (i < 0xc0)
897 break;
898 if (i < 0xd0) {
899 tempo = i - 0xbf;
900 continue;
902 if (i < 0xe0) {
903 pattern_offset[ch]++;
904 break;
906 if (i < 0xf0) {
907 pattern_offset[ch] += 2;
908 break;
910 if (i < 0xff) {
911 blank_rows[ch] = i - 0xf0;
912 break;
914 blank_rows[ch] = 64;
915 break;
918 player_calls += tempo;
920 pos += 17;
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)))
929 V(int, i);
930 V(int, last_pos);
931 V(int, c);
932 if (module_len < 0x3a4)
933 return FALSE;
934 module_info _ type = ASAP_TYPE_TM2;
935 if (!load_native(ast, module_info, module, module_len, GET_PLAYER(tm2)))
936 return FALSE;
937 i = module[0x25];
938 if (i < 1 || i > 4)
939 return FALSE;
940 module_info _ fastplay = perframe2fastplay[i - 1];
941 module_info _ player = 0x500;
942 if (module[0x1f] != 0)
943 module_info _ channels = 2;
944 last_pos = 0xffff;
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)
957 return FALSE;
958 /* skip trailing stop/jump commands */
959 do {
960 if (last_pos <= 0)
961 return FALSE;
962 last_pos -= 17;
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);
972 return TRUE;
975 #endif /* ASAP_ONLY_SAP */
977 PRIVATE FUNC(abool, has_string_at, (P(CONST BYTEARRAY, module), P(int, module_index), P(STRING, s)))
979 V(int, i);
980 V(int, n) = strlen(s);
981 for (i = 0; i < n; i++)
982 if (module[module_index + i] != CHARCODEAT(s, i))
983 return FALSE;
984 return TRUE;
987 PRIVATE FUNC(STRING, parse_text, (P(OUT_STRING, dest), P(CONST BYTEARRAY, module), P(int, module_index)))
989 V(int, i);
990 if (module[module_index] != CHARCODE('"'))
991 return NULL;
992 if (has_string_at(module, module_index + 1, "<?>\""))
993 return dest;
994 for (i = 0; ; i++) {
995 V(int, c) = module[module_index + 1 + i];
996 if (c == CHARCODE('"'))
997 break;
998 if (c < 32 || c >= 127)
999 return NULL;
1001 BYTES_TO_STRING(dest, module, module_index + 1, i);
1002 return dest;
1005 PRIVATE FUNC(int, parse_dec, (P(CONST BYTEARRAY, module), P(int, module_index), P(int, maxval)))
1007 V(int, r);
1008 if (module[module_index] == 0xd)
1009 return -1;
1010 for (r = 0;;) {
1011 V(int, c) = module[module_index++];
1012 if (c == 0xd)
1013 break;
1014 if (c < CHARCODE('0') || c > CHARCODE('9'))
1015 return -1;
1016 r = 10 * r + c - 48;
1017 if (r > maxval)
1018 return -1;
1020 return r;
1023 PRIVATE FUNC(int, parse_hex, (P(CONST BYTEARRAY, module), P(int, module_index)))
1025 V(int, r);
1026 if (module[module_index] == 0xd)
1027 return -1;
1028 for (r = 0;;) {
1029 V(int, c) = module[module_index++];
1030 if (c == 0xd)
1031 break;
1032 if (r > 0xfff)
1033 return -1;
1034 r <<= 4;
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;
1041 else
1042 return -1;
1044 return r;
1047 FUNC(int, ASAP_ParseDuration, (P(STRING, s)))
1049 V(int, i) = 0;
1050 V(int, r);
1051 V(int, d);
1052 V(int, n) = strlen(s);
1053 #define PARSE_DIGIT(maxdig, retifnot) \
1054 if (i >= n) \
1055 return retifnot; \
1056 d = CHARCODEAT(s, i) - 48; \
1057 if (d < 0 || d > maxdig) \
1058 return -1; \
1059 i++;
1061 PARSE_DIGIT(9, -1);
1062 r = d;
1063 if (i < n) {
1064 d = CHARCODEAT(s, i) - 48;
1065 if (d >= 0 && d <= 9) {
1066 i++;
1067 r = 10 * r + d;
1069 if (i < n && CHARAT(s, i) == ':') {
1070 i++;
1071 PARSE_DIGIT(5, -1);
1072 r = (6 * r + d) * 10;
1073 PARSE_DIGIT(9, -1);
1074 r += d;
1077 r *= 1000;
1078 if (i >= n)
1079 return r;
1080 if (CHARAT(s, i) != '.')
1081 return -1;
1082 i++;
1083 PARSE_DIGIT(9, -1);
1084 r += 100 * d;
1085 PARSE_DIGIT(9, r);
1086 r += 10 * d;
1087 PARSE_DIGIT(9, r);
1088 r += d;
1089 return r;
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);
1096 V(int, type) = 0;
1097 V(int, duration_index) = 0;
1098 if (!has_string_at(module, 0, "SAP\r\n"))
1099 return FALSE;
1100 module_info _ fastplay = -1;
1101 module_index = 5;
1102 while (UBYTE(module[module_index]) != 0xff) {
1103 if (module_index + 8 >= module_len)
1104 return FALSE;
1105 #define TAG_IS(s) has_string_at(module, module_index, s)
1106 #ifdef C
1107 #define SET_TEXT(v, i) if (parse_text(v, module, module_index + i) == NULL) return FALSE
1108 #else
1109 #define SET_TEXT(v, i) v = parse_text(v, module, module_index + i); if (v == NULL) return FALSE
1110 #endif
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 ")) {
1133 V(int, i);
1134 #ifdef C
1135 char s[ASAP_DURATION_CHARS];
1136 #else
1137 V(STRING, s);
1138 #endif
1139 module_index += 5;
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;
1143 i -= 5;
1145 #ifdef C
1146 if (i >= ASAP_DURATION_CHARS)
1147 return FALSE;
1148 #endif
1149 BYTES_TO_STRING(s, module, module_index, i);
1150 i = ASAP_ParseDuration(s);
1151 if (i < 0 || duration_index >= ASAP_SONGS_MAX)
1152 return FALSE;
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)
1172 return FALSE;
1173 module_info _ channels = 2;
1176 while (module[module_index++] != 0x0d) {
1177 if (module_index >= module_len)
1178 return FALSE;
1180 if (module[module_index++] != 0x0a)
1181 return FALSE;
1183 if (module_info _ default_song >= module_info _ songs)
1184 return FALSE;
1185 switch (type) {
1186 case CHARCODE('B'):
1187 if (module_info _ player < 0 || module_info _ init < 0)
1188 return FALSE;
1189 module_info _ type = ASAP_TYPE_SAP_B;
1190 break;
1191 case CHARCODE('C'):
1192 if (module_info _ player < 0 || module_info _ music < 0)
1193 return FALSE;
1194 module_info _ type = ASAP_TYPE_SAP_C;
1195 break;
1196 case CHARCODE('D'):
1197 if (module_info _ init < 0)
1198 return FALSE;
1199 module_info _ type = ASAP_TYPE_SAP_D;
1200 break;
1201 case CHARCODE('S'):
1202 if (module_info _ init < 0)
1203 return FALSE;
1204 module_info _ type = ASAP_TYPE_SAP_S;
1205 module_info _ fastplay = 78;
1206 break;
1207 default:
1208 return FALSE;
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)
1213 return FALSE;
1214 if (UBYTE(module[module_index + 1]) != 0xff)
1215 return FALSE;
1216 module_info _ header_len = module_index;
1217 return TRUE;
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))
1226 return FALSE;
1227 if (ast == NULL)
1228 return TRUE;
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)
1235 return FALSE;
1236 module_index += 4;
1237 COPY_ARRAY(ast _ memory, start_addr, module, module_index, block_len);
1238 module_index += block_len;
1239 if (module_index == module_len)
1240 return TRUE;
1241 if (module_index + 7 <= module_len
1242 && UBYTE(module[module_index]) == 0xff && UBYTE(module[module_index + 1]) == 0xff)
1243 module_index += 2;
1245 return FALSE;
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);
1253 V(int, ext) = 0;
1254 while (--i > 0) {
1255 V(char, c) = CHARAT(filename, i);
1256 if (c <= ' ' || c > 'z')
1257 return 0;
1258 if (c == '.')
1259 return ext | 0x202020;
1260 ext = (ext << 8) + CHARCODE(c);
1262 return 0;
1265 PRIVATE FUNC(abool, is_our_ext, (P(int, ext)))
1267 switch (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'):
1282 #endif
1283 return TRUE;
1284 default:
1285 return FALSE;
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)))
1305 V(int, i);
1306 V(int, len) = strlen(filename);
1307 V(int, basename) = 0;
1308 V(int, ext) = -1;
1309 for (i = 0; i < len; i++) {
1310 V(char, c) = CHARAT(filename, i);
1311 if (c == '/' || c == '\\') {
1312 basename = i + 1;
1313 ext = -1;
1315 else if (c == '.')
1316 ext = i;
1318 if (ext < 0)
1319 return FALSE;
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);
1366 #endif
1367 default:
1368 return FALSE;
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)))
1385 /* Set up ast */
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);
1404 ast _ cpu_s = 0xfd;
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;
1426 ast _ consol = 8;
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);
1432 ast _ cycle = 0;
1433 ast _ cpu_nz = 0;
1434 ast _ cpu_c = 0;
1435 ast _ cpu_vdi = 0;
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;
1441 ast _ irqst = 0xff;
1442 switch (ast _ module_info->type) {
1443 case ASAP_TYPE_SAP_B:
1444 call_6502_init(ast, ast _ module_info->init, song, 0, 0);
1445 break;
1446 case ASAP_TYPE_SAP_C:
1447 #ifndef ASAP_ONLY_SAP
1448 case ASAP_TYPE_CMC:
1449 case ASAP_TYPE_CM3:
1450 case ASAP_TYPE_CMR:
1451 case ASAP_TYPE_CMS:
1452 #endif
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);
1455 break;
1456 case ASAP_TYPE_SAP_D:
1457 case ASAP_TYPE_SAP_S:
1458 ast _ cpu_a = song;
1459 ast _ cpu_x = 0x00;
1460 ast _ cpu_y = 0x00;
1461 ast _ cpu_s = 0xff;
1462 ast _ cpu_pc = ast _ module_info->init;
1463 break;
1464 #ifndef ASAP_ONLY_SAP
1465 case ASAP_TYPE_DLT:
1466 call_6502_init(ast, ast _ module_info->player + 0x100, 0x00, 0x00, ast _ module_info->song_pos[song]);
1467 break;
1468 case ASAP_TYPE_MPT:
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);
1471 break;
1472 case ASAP_TYPE_RMT:
1473 call_6502_init(ast, ast _ module_info->player, ast _ module_info->song_pos[song], ast _ module_info->music, ast _ module_info->music >> 8);
1474 break;
1475 case ASAP_TYPE_TMC:
1476 case ASAP_TYPE_TM2:
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;
1480 break;
1481 #endif
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);
1499 break;
1500 case ASAP_TYPE_SAP_C:
1501 #ifndef ASAP_ONLY_SAP
1502 case ASAP_TYPE_CMC:
1503 case ASAP_TYPE_CM3:
1504 case ASAP_TYPE_CMR:
1505 case ASAP_TYPE_CMS:
1506 #endif
1507 call_6502(ast, player + 6, ast _ module_info->fastplay);
1508 break;
1509 case ASAP_TYPE_SAP_D:
1510 if (player >= 0) {
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);
1525 ast _ cpu_s = s;
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);
1535 break;
1536 case ASAP_TYPE_SAP_S:
1537 Cpu_RunScanlines(ast, ast _ module_info->fastplay);
1539 V(int, i) = dGetByte(0x45) - 1;
1540 dPutByte(0x45, i);
1541 if (i == 0)
1542 dPutByte(0xb07b, dGetByte(0xb07b) + 1);
1544 break;
1545 #ifndef ASAP_ONLY_SAP
1546 case ASAP_TYPE_DLT:
1547 call_6502(ast, player + 0x103, ast _ module_info->fastplay);
1548 break;
1549 case ASAP_TYPE_MPT:
1550 case ASAP_TYPE_RMT:
1551 case ASAP_TYPE_TM2:
1552 call_6502(ast, player + 3, ast _ module_info->fastplay);
1553 break;
1554 case ASAP_TYPE_TMC:
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);
1559 else
1560 call_6502(ast, player + 6, ast _ module_info->fastplay);
1561 break;
1562 #endif
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)
1570 return FALSE;
1572 else
1573 ast _ silence_cycles_counter = ast _ silence_cycles;
1575 return TRUE;
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(' ');
1632 buffer[16] = 16;
1633 buffer[17] = 0;
1634 buffer[18] = 0;
1635 buffer[19] = 0;
1636 buffer[20] = 1;
1637 buffer[21] = 0;
1638 buffer[22] = CAST(byte) ast _ module_info->channels;
1639 buffer[23] = 0;
1640 serialize_int(buffer, 24, ASAP_SAMPLE_RATE);
1641 serialize_int(buffer, 28, bytes_per_second);
1642 buffer[32] = CAST(byte) block_size;
1643 buffer[33] = 0;
1644 buffer[34] = CAST(byte) (8 << use_16bit);
1645 buffer[35] = 0;
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);
1659 V(int, block);
1660 if (ast _ silence_cycles > 0 && ast _ silence_cycles_counter <= 0)
1661 return 0;
1662 #ifdef ACTIONSCRIPT
1663 block_shift = 0;
1664 #else
1665 block_shift = (ast _ module_info->channels - 1) + (format != ASAP_FORMAT_U8 ? 1 : 0);
1666 #endif
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;
1673 block = 0;
1674 do {
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;
1678 block += 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 */
1690 #ifdef C
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)
1700 char *dest = NULL;
1701 while (*filename != '\0') {
1702 if (*filename == '/' || *filename == '\\')
1703 dest = NULL;
1704 else if (*filename == '.')
1705 dest = filename + 1;
1706 filename++;
1708 if (dest == NULL)
1709 return FALSE;
1710 strcpy(dest, ext);
1711 return TRUE;
1714 static byte *put_string(byte *dest, const char *str)
1716 while (*str != '\0')
1717 *dest++ = *str++;
1718 return dest;
1721 static byte *put_dec(byte *dest, int value)
1723 if (value >= 10) {
1724 dest = put_dec(dest, value / 10);
1725 value %= 10;
1727 *dest++ = '0' + value;
1728 return dest;
1731 static byte *put_text_tag(byte *dest, const char *tag, const char *value)
1733 dest = put_string(dest, tag);
1734 *dest++ = '"';
1735 if (*value == '\0')
1736 value = "<?>";
1737 while (*value != '\0') {
1738 if (*value < ' ' || *value > 'z' || *value == '"' || *value == '`')
1739 return NULL;
1740 *dest++ = *value++;
1742 *dest++ = '"';
1743 *dest++ = '\r';
1744 *dest++ = '\n';
1745 return dest;
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);
1752 *dest++ = '\r';
1753 *dest++ = '\n';
1754 return dest;
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);
1761 if (dest == NULL)
1762 return NULL;
1763 dest = put_text_tag(dest, "NAME ", module_info->name);
1764 if (dest == NULL)
1765 return NULL;
1766 dest = put_text_tag(dest, "DATE ", module_info->date);
1767 if (dest == NULL)
1768 return NULL;
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");
1776 return dest;
1779 static char *two_digits(char *s, int x)
1781 s[0] = '0' + x / 10;
1782 s[1] = '0' + x % 10;
1783 return s + 2;
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);
1791 *s++ = ':';
1792 s = two_digits(s, seconds % 60);
1793 duration %= 1000;
1794 if (duration != 0) {
1795 *s++ = '.';
1796 s = two_digits(s, duration / 10);
1797 duration %= 10;
1798 if (duration != 0)
1799 *s++ = '0' + duration;
1802 *s = '\0';
1805 static byte *put_durations(byte *dest, const ASAP_ModuleInfo *module_info)
1807 int song;
1808 for (song = 0; song < module_info->songs; song++) {
1809 if (module_info->durations[song] < 0)
1810 break;
1811 dest = put_string(dest, "TIME ");
1812 ASAP_DurationToString((char *) dest, module_info->durations[song]);
1813 while (*dest != '\0')
1814 dest++;
1815 if (module_info->loops[song])
1816 dest = put_string(dest, " LOOP");
1817 *dest++ = '\r';
1818 *dest++ = '\n';
1820 return dest;
1823 int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const BYTEARRAY module, int module_len, BYTEARRAY out_module)
1825 byte *dest;
1826 int i;
1827 if (memcmp(module, "SAP\r\n", 5) != 0)
1828 return -1;
1829 dest = start_sap_header(out_module, module_info);
1830 if (dest == NULL)
1831 return -1;
1832 i = 5;
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);
1843 else {
1844 int b;
1845 do {
1846 b = module[i++];
1847 *dest++ = b;
1848 } while (i < module_len && b != 0x0a);
1851 dest = put_durations(dest, module_info);
1852 module_len -= i;
1853 memcpy(dest, module + i, module_len);
1854 dest += 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)
1867 (void) filename;
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)
1871 return "dlt";
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)
1875 return "rmt";
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)))
1879 return "tmc";
1880 if (module_info->init == TM2_INIT)
1881 return "tm2";
1882 break;
1883 case ASAP_TYPE_SAP_C:
1884 if (module_info->player == 0x500 || module_info->player == 0xf500) {
1885 if (module_info->fastplay == 156)
1886 return "dmc";
1887 if (module_info->channels > 1)
1888 return "cms";
1889 if (module[module_len - 170] == 0x1e)
1890 return "cmr";
1891 if (module[module_len - 909] == 0x30)
1892 return "cm3";
1893 return "cmc";
1895 break;
1896 case ASAP_TYPE_CMC:
1897 case ASAP_TYPE_CM3:
1898 case ASAP_TYPE_CMR:
1899 case ASAP_TYPE_CMS:
1900 case ASAP_TYPE_DLT:
1901 case ASAP_TYPE_MPT:
1902 case ASAP_TYPE_RMT:
1903 case ASAP_TYPE_TMC:
1904 case ASAP_TYPE_TM2:
1905 return "sap";
1906 default:
1907 break;
1909 return NULL;
1912 static byte *put_hex_tag(byte *dest, const char *tag, int value)
1914 int i;
1915 if (value < 0)
1916 return dest;
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));
1922 *dest++ = '\r';
1923 *dest++ = '\n';
1924 return dest;
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);
1930 if (dest == NULL)
1931 return NULL;
1932 dest = put_string(dest, "TYPE ");
1933 *dest++ = type;
1934 *dest++ = '\r';
1935 *dest++ = '\n';
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);
1942 return dest;
1945 int ASAP_Convert(
1946 const char *filename, const ASAP_ModuleInfo *module_info,
1947 const BYTEARRAY module, int module_len, BYTEARRAY out_module)
1949 (void) filename;
1950 int out_len;
1951 byte *dest;
1952 int addr;
1953 int player;
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)
1961 return -1;
1962 memcpy(out_module, module + module_info->header_len, out_len);
1963 return out_len;
1964 case ASAP_TYPE_CMC:
1965 case ASAP_TYPE_CM3:
1966 case ASAP_TYPE_CMR:
1967 case ASAP_TYPE_CMS:
1968 dest = put_sap_header(out_module, module_info, 'C', module_info->music, -1, module_info->player);
1969 if (dest == NULL)
1970 return -1;
1971 memcpy(dest, module, module_len);
1972 dest[0] = 0xff; /* some modules start with zeros */
1973 dest[1] = 0xff;
1974 dest += module_len;
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;
1983 else {
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;
1990 case ASAP_TYPE_DLT:
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);
1995 else {
1996 addr = module_info->player - 5;
1997 dest = put_sap_header(out_module, module_info, 'B', -1, addr, module_info->player + 0x103);
1999 if (dest == NULL)
2000 return -1;
2001 memcpy(dest, module, module_len);
2002 if (module_len == 0x2c06) {
2003 dest[4] = 0;
2004 dest[5] = 0x4c;
2005 dest[0x2c06] = 0;
2007 dest += 0x2c07;
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);
2020 else {
2021 *dest++ = 0xa0; /* ldy #0 */
2022 *dest++ = 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;
2030 case ASAP_TYPE_MPT:
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);
2035 else {
2036 addr = module_info->player - 13;
2037 dest = put_sap_header(out_module, module_info, 'B', -1, addr, module_info->player + 3);
2039 if (dest == NULL)
2040 return -1;
2041 memcpy(dest, module, module_len);
2042 dest += 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 */
2057 *dest++ = 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);
2068 else {
2069 *dest++ = 0xa2; /* ldx #0 */
2070 *dest++ = 0;
2072 *dest++ = 0xa9; /* lda #2 */
2073 *dest++ = 2;
2074 memcpy(dest, mpt_obx + 6, sizeof(mpt_obx) - 6);
2075 dest += sizeof(mpt_obx) - 6;
2076 return dest - out_module;
2077 case ASAP_TYPE_RMT:
2078 dest = put_sap_header(out_module, module_info, 'B', -1, RMT_INIT, module_info->player + 3);
2079 if (dest == NULL)
2080 return -1;
2081 memcpy(dest, module, module_len);
2082 dest += 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);
2094 else {
2095 *dest++ = (byte) (RMT_INIT + 8);
2096 *dest++ = (byte) ((RMT_INIT + 8) >> 8);
2097 *dest++ = 0xa9; /* lda #0 */
2098 *dest++ = 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;
2115 else {
2116 memcpy(dest, rmt8_obx + 2, sizeof(rmt8_obx) - 2);
2117 dest += sizeof(rmt8_obx) - 2;
2119 return dest - out_module;
2120 case ASAP_TYPE_TMC:
2121 player = module_info->player + tmc_player[module[0x25] - 1];
2122 addr = player + tmc_init[module[0x25] - 1];
2123 if (module_info->songs != 1)
2124 addr -= 3;
2125 dest = put_sap_header(out_module, module_info, 'B', -1, addr, player);
2126 if (dest == NULL)
2127 return -1;
2128 memcpy(dest, module, module_len);
2129 dest += 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 */
2141 *dest++ = 0x70;
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 */
2149 *dest++ = 0;
2151 else {
2152 *dest++ = 0xa9; /* lda #$60 */
2153 *dest++ = 0x60;
2155 switch (module[0x25]) {
2156 case 2:
2157 *dest++ = 0x06; /* asl 0 */
2158 *dest++ = 0;
2159 *dest++ = 0x4c; /* jmp player */
2160 *dest++ = (byte) module_info->player;
2161 *dest++ = (byte) (module_info->player >> 8);
2162 *dest++ = 0xa5; /* lda 0 */
2163 *dest++ = 0;
2164 *dest++ = 0xe6; /* inc 0 */
2165 *dest++ = 0;
2166 *dest++ = 0x4a; /* lsr @ */
2167 *dest++ = 0x90; /* bcc player+3 */
2168 *dest++ = 5;
2169 *dest++ = 0xb0; /* bcs player+6 */
2170 *dest++ = 6;
2171 break;
2172 case 3:
2173 case 4:
2174 *dest++ = 0xa0; /* ldy #1 */
2175 *dest++ = 1;
2176 *dest++ = 0x84; /* sty 0 */
2177 *dest++ = 0;
2178 *dest++ = 0xd0; /* bne player */
2179 *dest++ = 10;
2180 *dest++ = 0xc6; /* dec 0 */
2181 *dest++ = 0;
2182 *dest++ = 0xd0; /* bne player+6 */
2183 *dest++ = 12;
2184 *dest++ = 0xa0; /* ldy #3 */
2185 *dest++ = module[0x25];
2186 *dest++ = 0x84; /* sty 0 */
2187 *dest++ = 0;
2188 *dest++ = 0xd0; /* bne player+3 */
2189 *dest++ = 3;
2190 break;
2191 default:
2192 break;
2194 memcpy(dest, tmc_obx + 6, sizeof(tmc_obx) - 6);
2195 dest += sizeof(tmc_obx) - 6;
2196 return dest - out_module;
2197 case ASAP_TYPE_TM2:
2198 dest = put_sap_header(out_module, module_info, 'B', -1, TM2_INIT, module_info->player + 3);
2199 if (dest == NULL)
2200 return -1;
2201 memcpy(dest, module, module_len);
2202 dest += 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 */
2210 else {
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 */
2219 *dest++ = 0x70;
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 */
2227 *dest++ = 0;
2229 else {
2230 *dest++ = 0xa9; /* lda #0 */
2231 *dest++ = 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;
2240 default:
2241 return -1;
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))
2256 return FALSE;
2257 if (date[2] == '/') {
2258 date += 3;
2259 if (!has_two_digits(date))
2260 return FALSE;
2261 if (date[2] == '/') {
2262 date += 3;
2263 if (!has_two_digits(date))
2264 return FALSE;
2267 if (!has_two_digits(date + 2) || date[4] != '\0')
2268 return FALSE;
2269 memcpy(year, date, 5);
2270 return TRUE;
2273 #endif /* C */