summaryrefslogtreecommitdiff
path: root/apps/codecs/libasap/asap.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libasap/asap.c')
-rw-r--r--apps/codecs/libasap/asap.c1796
1 files changed, 996 insertions, 800 deletions
diff --git a/apps/codecs/libasap/asap.c b/apps/codecs/libasap/asap.c
index 31de730d93..87b537ef63 100644
--- a/apps/codecs/libasap/asap.c
+++ b/apps/codecs/libasap/asap.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * asap.c - ASAP engine 2 * asap.c - ASAP engine
3 * 3 *
4 * Copyright (C) 2005-2008 Piotr Fusik 4 * Copyright (C) 2005-2010 Piotr Fusik
5 * 5 *
6 * This file is part of ASAP (Another Slight Atari Player), 6 * This file is part of ASAP (Another Slight Atari Player),
7 * see http://asap.sourceforge.net 7 * see http://asap.sourceforge.net
@@ -20,70 +20,48 @@
20 * along with ASAP; if not, write to the Free Software Foundation, Inc., 20 * along with ASAP; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */ 22 */
23#include "codeclib.h"
24#if !defined(JAVA) && !defined(CSHARP)
25#include <string.h>
26#endif
27 23
28#include "asap_internal.h" 24#include "asap_internal.h"
29#if !defined(JAVA) && !defined(CSHARP)
30#include "players.h"
31#endif
32
33#define memcpy ci->memcpy
34#define memcmp ci->memcmp
35#define memset ci->memset
36#define strcpy ci->strcpy
37#define strcmp ci->strcmp
38#define strstr ci->strcasestr
39
40
41#define CMR_BASS_TABLE_OFFSET 0x70f
42
43CONST_LOOKUP(byte, cmr_bass_table) = {
44 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E,
45 0x38, 0x35, (byte) 0x88, 0x7F, 0x79, 0x73, 0x6C, 0x67,
46 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F,
47 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28,
48 0x25, 0x24, 0x21, 0x1F, 0x1E
49};
50 25
51ASAP_FUNC int ASAP_GetByte(ASAP_State PTR ast, int addr) 26FUNC(int, ASAP_GetByte, (P(ASAP_State PTR, ast), P(int, addr)))
52{ 27{
53 switch (addr & 0xff0f) { 28 switch (addr & 0xff0f) {
54 case 0xd20a: 29 case 0xd20a:
55 return PokeySound_GetRandom(ast, addr); 30 return PokeySound_GetRandom(ast, addr, ast _ cycle);
56 case 0xd20e: 31 case 0xd20e:
57 if ((addr & AST extra_pokey_mask) != 0) 32 if ((addr & ast _ extra_pokey_mask) != 0) {
33 /* interrupts in the extra POKEY not emulated at the moment */
58 return 0xff; 34 return 0xff;
59 return AST irqst; 35 }
36 return ast _ irqst;
60 case 0xd20f: 37 case 0xd20f:
38 /* just because some SAP files rely on this */
61 return 0xff; 39 return 0xff;
62 case 0xd40b: 40 case 0xd40b:
63 return AST scanline_number >> 1; 41 return ast _ scanline_number >> 1;
64 default: 42 default:
65 return dGetByte(addr); 43 return dGetByte(addr);
66 } 44 }
67} 45}
68 46
69ASAP_FUNC void ASAP_PutByte(ASAP_State PTR ast, int addr, int data) 47FUNC(void, ASAP_PutByte, (P(ASAP_State PTR, ast), P(int, addr), P(int, data)))
70{ 48{
71 if ((addr >> 8) == 0xd2) { 49 if ((addr >> 8) == 0xd2) {
72 if ((addr & (AST extra_pokey_mask + 0xf)) == 0xe) { 50 if ((addr & (ast _ extra_pokey_mask + 0xf)) == 0xe) {
73 AST irqst |= data ^ 0xff; 51 ast _ irqst |= data ^ 0xff;
74#define SET_TIMER_IRQ(ch) \ 52#define SET_TIMER_IRQ(ch) \
75 if ((data & AST irqst & ch) != 0) { \ 53 if ((data & ast _ irqst & ch) != 0) { \
76 if (AST timer##ch##_cycle == NEVER) { \ 54 if (ast _ timer##ch##_cycle == NEVER) { \
77 int t = AST base_pokey.tick_cycle##ch; \ 55 V(int, t) = ast _ base_pokey.tick_cycle##ch; \
78 while (t < AST cycle) \ 56 while (t < ast _ cycle) \
79 t += AST base_pokey.period_cycles##ch; \ 57 t += ast _ base_pokey.period_cycles##ch; \
80 AST timer##ch##_cycle = t; \ 58 ast _ timer##ch##_cycle = t; \
81 if (AST nearest_event_cycle > t) \ 59 if (ast _ nearest_event_cycle > t) \
82 AST nearest_event_cycle = t; \ 60 ast _ nearest_event_cycle = t; \
83 } \ 61 } \
84 } \ 62 } \
85 else \ 63 else \
86 AST timer##ch##_cycle = NEVER; 64 ast _ timer##ch##_cycle = NEVER;
87 SET_TIMER_IRQ(1); 65 SET_TIMER_IRQ(1);
88 SET_TIMER_IRQ(2); 66 SET_TIMER_IRQ(2);
89 SET_TIMER_IRQ(4); 67 SET_TIMER_IRQ(4);
@@ -92,136 +70,120 @@ ASAP_FUNC void ASAP_PutByte(ASAP_State PTR ast, int addr, int data)
92 PokeySound_PutByte(ast, addr, data); 70 PokeySound_PutByte(ast, addr, data);
93 } 71 }
94 else if ((addr & 0xff0f) == 0xd40a) { 72 else if ((addr & 0xff0f) == 0xd40a) {
95 if (AST cycle <= AST next_scanline_cycle - 8) 73 if (ast _ cycle <= ast _ next_scanline_cycle - 8)
96 AST cycle = AST next_scanline_cycle - 8; 74 ast _ cycle = ast _ next_scanline_cycle - 8;
75 else
76 ast _ cycle = ast _ next_scanline_cycle + 106;
77 }
78 else if ((addr & 0xff00) == ast _ module_info.covox_addr) {
79 V(PokeyState PTR, pst);
80 addr &= 3;
81 if (addr == 0 || addr == 3)
82 pst = ADDRESSOF ast _ base_pokey;
97 else 83 else
98 AST cycle = AST next_scanline_cycle + 106; 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);
87 }
88 else if ((addr & 0xff1f) == 0xd01f) {
89 V(int, sample) = CYCLE_TO_SAMPLE(ast _ cycle);
90 V(int, delta);
91 data &= 8;
92 /* NOT data - ast _ consol; reverse to the POKEY sound */
93 delta = (ast _ consol - data) << DELTA_SHIFT_GTIA;
94 ast _ consol = data;
95 ast _ base_pokey.delta_buffer[sample] += delta;
96 ast _ extra_pokey.delta_buffer[sample] += delta;
99 } 97 }
100 else 98 else
101 dPutByte(addr, data); 99 dPutByte(addr, data);
102} 100}
103 101
104#define MAX_SONGS 32 102#define UWORD(array, index) (UBYTE(array[index]) + (UBYTE(array[(index) + 1]) << 8))
105 103
106CONST_LOOKUP(int, perframe2fastplay) = { 312, 312 / 2, 312 / 3, 312 / 4 }; 104#ifndef ASAP_ONLY_SAP
107 105
108FILE_FUNC abool load_native(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 106#ifndef JAVA
109 const byte ARRAY module, int module_len, ASAP_OBX player) 107#include "players.h"
110{
111#if defined(JAVA) || defined(CSHARP)
112 try
113#endif 108#endif
114 { 109
115 int player_last_byte; 110#define CMR_BASS_TABLE_OFFSET 0x70f
116 int block_len; 111
117 if (UBYTE(module[0]) != 0xff || UBYTE(module[1]) != 0xff) 112CONST_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
118END_CONST_ARRAY;
119
120CONST_ARRAY(int, perframe2fastplay)
121 312, 312 / 2, 312 / 3, 312 / 4
122END_CONST_ARRAY;
123
124/* Loads native module (anything except SAP) and 6502 player routine. */
125PRIVATE 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)))
128{
129 V(int, player_last_byte);
130 V(int, music_last_byte);
131 V(int, block_len);
132 if ((UBYTE(module[0]) != 0xff || UBYTE(module[1]) != 0xff)
133 && (module[0] != 0 || module[1] != 0)) /* some CMC and clones start with zeros */
134 return FALSE;
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)
139 return FALSE;
140 music_last_byte = UWORD(module, 4);
141 if (module_info _ music <= 0xd7ff && music_last_byte >= 0xd000)
142 return FALSE;
143 block_len = music_last_byte + 1 - module_info _ music;
144 if (6 + block_len != module_len) {
145 V(int, info_addr);
146 V(int, info_len);
147 if (module_info _ type != ASAP_TYPE_RMT || 11 + block_len > module_len)
118 return FALSE; 148 return FALSE;
119#ifdef JAVA 149 /* allow optional info for Raster Music Tracker */
120 try { 150 info_addr = UWORD(module, 6 + block_len);
121 player.read(); 151 if (info_addr != module_info _ music + block_len)
122 player.read(); 152 return FALSE;
123 MODULE_INFO player = player.read(); 153 info_len = UWORD(module, 8 + block_len) + 1 - info_addr;
124 MODULE_INFO player += player.read() << 8; 154 if (10 + block_len + info_len != module_len)
125 player_last_byte = player.read();
126 player_last_byte += player.read() << 8;
127 } catch (IOException e) {
128 throw new RuntimeException();
129 }
130#elif defined(CSHARP)
131 player.ReadByte();
132 player.ReadByte();
133 MODULE_INFO player = player.ReadByte();
134 MODULE_INFO player += player.ReadByte() << 8;
135 player_last_byte = player.ReadByte();
136 player_last_byte += player.ReadByte() << 8;
137#else
138 MODULE_INFO player = UBYTE(player[2]) + (UBYTE(player[3]) << 8);
139 player_last_byte = UBYTE(player[4]) + (UBYTE(player[5]) << 8);
140#endif
141 MODULE_INFO music = UBYTE(module[2]) + (UBYTE(module[3]) << 8);
142 if (MODULE_INFO music <= player_last_byte)
143 return FALSE; 155 return FALSE;
144 block_len = UBYTE(module[4]) + (UBYTE(module[5]) << 8) + 1 - MODULE_INFO music;
145 if (6 + block_len != module_len) {
146 int info_addr;
147 int info_len;
148 if (MODULE_INFO type != 'r' || 11 + block_len > module_len)
149 return FALSE;
150 /* allow optional info for Raster Music Tracker */
151 info_addr = UBYTE(module[6 + block_len]) + (UBYTE(module[7 + block_len]) << 8);
152 if (info_addr != MODULE_INFO music + block_len)
153 return FALSE;
154 info_len = UBYTE(module[8 + block_len]) + (UBYTE(module[9 + block_len]) << 8) + 1 - info_addr;
155 if (10 + block_len + info_len != module_len)
156 return FALSE;
157 }
158 if (ast != NULL) {
159 COPY_ARRAY(AST memory, MODULE_INFO music, module, 6, block_len);
160#ifdef JAVA
161 int addr = MODULE_INFO player;
162 do {
163 int i;
164 try {
165 i = player.read(AST memory, addr, player_last_byte + 1 - addr);
166 } catch (IOException e) {
167 throw new RuntimeException();
168 }
169 if (i <= 0)
170 throw new RuntimeException();
171 addr += i;
172 } while (addr <= player_last_byte);
173#elif defined(CSHARP)
174 int addr = MODULE_INFO player;
175 do {
176 int i = player.Read(AST memory, addr, player_last_byte + 1 - addr);
177 if (i <= 0)
178 throw new Exception();
179 addr += i;
180 } while (addr <= player_last_byte);
181#else
182 COPY_ARRAY(AST memory, MODULE_INFO player, player, 6, player_last_byte + 1 - MODULE_INFO player);
183#endif
184 }
185 return TRUE;
186 }
187#ifdef JAVA
188 finally {
189 try {
190 player.close();
191 } catch (IOException e) {
192 throw new RuntimeException();
193 }
194 } 156 }
195#elif defined(CSHARP) 157 if (ast != NULL) {
196 finally { 158 COPY_ARRAY(ast _ memory, module_info _ music, module, 6, block_len);
197 player.Close(); 159 COPY_ARRAY(ast _ memory, module_info _ player, player, 6, player_last_byte + 1 - module_info _ player);
198 } 160 }
199#endif 161 return TRUE;
200} 162}
201 163
202FILE_FUNC void set_song_duration(ASAP_ModuleInfo PTR module_info, int player_calls) 164PRIVATE FUNC(void, set_song_duration, (P(ASAP_ModuleInfo PTR, module_info), P(int, player_calls)))
203{ 165{
204 MODULE_INFO durations[MODULE_INFO songs] = (int) (player_calls * MODULE_INFO fastplay * 114000.0 / 1773447); 166 module_info _ durations[module_info _ songs] = TO_INT(player_calls * module_info _ fastplay * 114000.0 / 1773447);
205 MODULE_INFO songs++; 167 module_info _ songs++;
206} 168}
207 169
208#define SEEN_THIS_CALL 1 170#define SEEN_THIS_CALL 1
209#define SEEN_BEFORE 2 171#define SEEN_BEFORE 2
210#define SEEN_REPEAT 3 172#define SEEN_REPEAT 3
211 173
212FILE_FUNC void parse_cmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) 174PRIVATE FUNC(void, parse_cmc_song, (P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos)))
213{ 175{
214 int tempo = UBYTE(module[0x19]); 176 V(int, tempo) = UBYTE(module[0x19]);
215 int player_calls = 0; 177 V(int, player_calls) = 0;
216 int rep_start_pos = 0; 178 V(int, rep_start_pos) = 0;
217 int rep_end_pos = 0; 179 V(int, rep_end_pos) = 0;
218 int rep_times = 0; 180 V(int, rep_times) = 0;
219 NEW_ARRAY(byte, seen, 0x55); 181 NEW_ARRAY(byte, seen, 0x55);
220 INIT_ARRAY(seen); 182 INIT_ARRAY(seen);
221 while (pos >= 0 && pos < 0x55) { 183 while (pos >= 0 && pos < 0x55) {
222 int p1; 184 V(int, p1);
223 int p2; 185 V(int, p2);
224 int p3; 186 V(int, p3);
225 if (pos == rep_end_pos && rep_times > 0) { 187 if (pos == rep_end_pos && rep_times > 0) {
226 for (p1 = 0; p1 < 0x55; p1++) 188 for (p1 = 0; p1 < 0x55; p1++)
227 if (seen[p1] == SEEN_THIS_CALL || seen[p1] == SEEN_REPEAT) 189 if (seen[p1] == SEEN_THIS_CALL || seen[p1] == SEEN_REPEAT)
@@ -231,7 +193,7 @@ FILE_FUNC void parse_cmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
231 } 193 }
232 if (seen[pos] != 0) { 194 if (seen[pos] != 0) {
233 if (seen[pos] != SEEN_THIS_CALL) 195 if (seen[pos] != SEEN_THIS_CALL)
234 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 196 module_info _ loops[module_info _ songs] = TRUE;
235 break; 197 break;
236 } 198 }
237 seen[pos] = SEEN_THIS_CALL; 199 seen[pos] = SEEN_THIS_CALL;
@@ -270,53 +232,145 @@ FILE_FUNC void parse_cmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
270 continue; 232 continue;
271 } 233 }
272 if (p1 == 0xe) { 234 if (p1 == 0xe) {
273 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 235 module_info _ loops[module_info _ songs] = TRUE;
274 break; 236 break;
275 } 237 }
276 p2 = rep_times > 0 ? SEEN_REPEAT : SEEN_BEFORE; 238 p2 = rep_times > 0 ? SEEN_REPEAT : SEEN_BEFORE;
277 for (p1 = 0; p1 < 0x55; p1++) 239 for (p1 = 0; p1 < 0x55; p1++)
278 if (seen[p1] == SEEN_THIS_CALL) 240 if (seen[p1] == SEEN_THIS_CALL)
279 seen[p1] = (byte) p2; 241 seen[p1] = CAST(byte) p2;
280 player_calls += tempo << 6; 242 player_calls += tempo * (module_info _ type == ASAP_TYPE_CM3 ? 48 : 64);
281 pos++; 243 pos++;
282 } 244 }
283 set_song_duration(module_info, player_calls); 245 set_song_duration(module_info, player_calls);
284} 246}
285 247
286FILE_FUNC abool parse_cmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 248PRIVATE FUNC(abool, parse_cmc, (
287 const byte ARRAY module, int module_len, abool cmr) 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)))
288{ 251{
289 int last_pos; 252 V(int, last_pos);
290 int pos; 253 V(int, pos);
291 if (module_len < 0x306) 254 if (module_len < 0x306)
292 return FALSE; 255 return FALSE;
293 MODULE_INFO type = cmr ? 'z' : 'c'; 256 module_info _ type = type;
294 if (!load_native(ast, module_info, module, module_len, GET_OBX(cmc))) 257 if (!load_native(ast, module_info, module, module_len, player))
295 return FALSE; 258 return FALSE;
296 if (ast != NULL && cmr) 259 if (ast != NULL && type == ASAP_TYPE_CMR)
297 COPY_ARRAY(AST memory, 0x500 + CMR_BASS_TABLE_OFFSET, cmr_bass_table, 0, sizeof(cmr_bass_table)); 260 COPY_ARRAY(ast _ memory, 0x500 + CMR_BASS_TABLE_OFFSET, cmr_bass_table, 0, sizeof(cmr_bass_table));
298 /* auto-detect number of subsongs */
299 last_pos = 0x54; 261 last_pos = 0x54;
300 while (--last_pos >= 0) { 262 while (--last_pos >= 0) {
301 if (UBYTE(module[0x206 + last_pos]) < 0xb0 263 if (UBYTE(module[0x206 + last_pos]) < 0xb0
302 || UBYTE(module[0x25b + last_pos]) < 0x40 264 || UBYTE(module[0x25b + last_pos]) < 0x40
303 || UBYTE(module[0x2b0 + last_pos]) < 0x40) 265 || UBYTE(module[0x2b0 + last_pos]) < 0x40)
304 break; 266 break;
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)
271 break;
272 }
305 } 273 }
306 MODULE_INFO songs = 0; 274 module_info _ songs = 0;
307 parse_cmc_song(module_info, module, 0); 275 parse_cmc_song(module_info, module, 0);
308 for (pos = 0; pos < last_pos && MODULE_INFO songs < MAX_SONGS; pos++) 276 for (pos = 0; pos < last_pos && module_info _ songs < ASAP_SONGS_MAX; pos++)
309 if (UBYTE(module[0x206 + pos]) == 0x8f || UBYTE(module[0x206 + pos]) == 0xef) 277 if (UBYTE(module[0x206 + pos]) == 0x8f || UBYTE(module[0x206 + pos]) == 0xef)
310 parse_cmc_song(module_info, module, pos + 1); 278 parse_cmc_song(module_info, module, pos + 1);
311 return TRUE; 279 return TRUE;
312} 280}
313 281
314FILE_FUNC void parse_mpt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, 282PRIVATE FUNC(abool, is_dlt_track_empty, (P(CONST BYTEARRAY, module), P(int, pos)))
315 abool ARRAY global_seen, int song_len, int pos) 283{
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;
288}
289
290PRIVATE FUNC(abool, is_dlt_pattern_end, (P(CONST BYTEARRAY, module), P(int, pos), P(int, i)))
291{
292 V(int, ch);
293 for (ch = 0; ch < 4; ch++) {
294 V(int, pattern) = UBYTE(module[0x2006 + (ch << 8) + pos]);
295 if (pattern < 64) {
296 V(int, offset) = 6 + (pattern << 7) + (i << 1);
297 if ((module[offset] & 0x80) == 0 && (module[offset + 1] & 0x80) != 0)
298 return TRUE;
299 }
300 }
301 return FALSE;
302}
303
304PRIVATE FUNC(void, parse_dlt_song, (
305 P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module),
306 P(BOOLARRAY, seen), P(int, pos)))
307{
308 V(int, player_calls) = 0;
309 V(abool, loop) = FALSE;
310 V(int, tempo) = 6;
311 while (pos < 128 && !seen[pos] && is_dlt_track_empty(module, pos))
312 seen[pos++] = TRUE;
313 module_info _ song_pos[module_info _ songs] = CAST(byte) pos;
314 while (pos < 128) {
315 V(int, p1);
316 if (seen[pos]) {
317 loop = TRUE;
318 break;
319 }
320 seen[pos] = TRUE;
321 p1 = module[0x2006 + pos];
322 if (p1 == 0x40 || is_dlt_track_empty(module, pos))
323 break;
324 if (p1 == 0x41)
325 pos = UBYTE(module[0x2086 + pos]);
326 else if (p1 == 0x42)
327 tempo = UBYTE(module[0x2086 + pos++]);
328 else {
329 V(int, i);
330 for (i = 0; i < 64 && !is_dlt_pattern_end(module, pos, i); i++)
331 player_calls += tempo;
332 pos++;
333 }
334 }
335 if (player_calls > 0) {
336 module_info _ loops[module_info _ songs] = loop;
337 set_song_duration(module_info, player_calls);
338 }
339}
340
341PRIVATE 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)))
344{
345 V(int, pos);
346 NEW_ARRAY(abool, seen, 128);
347 if (module_len == 0x2c06) {
348 if (ast != NULL)
349 ast _ memory[0x4c00] = 0;
350 }
351 else if (module_len != 0x2c07)
352 return FALSE;
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) {
356 return FALSE;
357 }
358 INIT_ARRAY(seen);
359 module_info _ songs = 0;
360 for (pos = 0; pos < 128 && module_info _ songs < ASAP_SONGS_MAX; pos++) {
361 if (!seen[pos])
362 parse_dlt_song(module_info, module, seen, pos);
363 }
364 return module_info _ songs > 0;
365}
366
367PRIVATE 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)))
316{ 370{
317 int addr_to_offset = UBYTE(module[2]) + (UBYTE(module[3]) << 8) - 6; 371 V(int, addr_to_offset) = UWORD(module, 2) - 6;
318 int tempo = UBYTE(module[0x1cf]); 372 V(int, tempo) = UBYTE(module[0x1cf]);
319 int player_calls = 0; 373 V(int, player_calls) = 0;
320 NEW_ARRAY(byte, seen, 256); 374 NEW_ARRAY(byte, seen, 256);
321 NEW_ARRAY(int, pattern_offset, 4); 375 NEW_ARRAY(int, pattern_offset, 4);
322 NEW_ARRAY(int, blank_rows, 4); 376 NEW_ARRAY(int, blank_rows, 4);
@@ -324,12 +378,12 @@ FILE_FUNC void parse_mpt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
324 INIT_ARRAY(seen); 378 INIT_ARRAY(seen);
325 INIT_ARRAY(blank_rows); 379 INIT_ARRAY(blank_rows);
326 while (pos < song_len) { 380 while (pos < song_len) {
327 int i; 381 V(int, i);
328 int ch; 382 V(int, ch);
329 int pattern_rows; 383 V(int, pattern_rows);
330 if (seen[pos] != 0) { 384 if (seen[pos] != 0) {
331 if (seen[pos] != SEEN_THIS_CALL) 385 if (seen[pos] != SEEN_THIS_CALL)
332 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 386 module_info _ loops[module_info _ songs] = TRUE;
333 break; 387 break;
334 } 388 }
335 seen[pos] = SEEN_THIS_CALL; 389 seen[pos] = SEEN_THIS_CALL;
@@ -345,7 +399,7 @@ FILE_FUNC void parse_mpt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
345 if (i >= 0x40) 399 if (i >= 0x40)
346 break; 400 break;
347 i <<= 1; 401 i <<= 1;
348 i = UBYTE(module[0x46 + i]) + (UBYTE(module[0x47 + i]) << 8); 402 i = UWORD(module, 0x46 + i);
349 pattern_offset[ch] = i == 0 ? 0 : i - addr_to_offset; 403 pattern_offset[ch] = i == 0 ? 0 : i - addr_to_offset;
350 blank_rows_counter[ch] = 0; 404 blank_rows_counter[ch] = 0;
351 } 405 }
@@ -386,20 +440,21 @@ FILE_FUNC void parse_mpt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
386 set_song_duration(module_info, player_calls); 440 set_song_duration(module_info, player_calls);
387} 441}
388 442
389FILE_FUNC abool parse_mpt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 443PRIVATE FUNC(abool, parse_mpt, (
390 const byte ARRAY module, int module_len) 444 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
445 P(CONST BYTEARRAY, module), P(int, module_len)))
391{ 446{
392 int track0_addr; 447 V(int, track0_addr);
393 int pos; 448 V(int, pos);
394 int song_len; 449 V(int, song_len);
395 /* seen[i] == TRUE if the track position i has been processed */ 450 /* seen[i] == TRUE if the track position i has been processed */
396 NEW_ARRAY(abool, global_seen, 256); 451 NEW_ARRAY(abool, global_seen, 256);
397 if (module_len < 0x1d0) 452 if (module_len < 0x1d0)
398 return FALSE; 453 return FALSE;
399 MODULE_INFO type = 'm'; 454 module_info _ type = ASAP_TYPE_MPT;
400 if (!load_native(ast, module_info, module, module_len, GET_OBX(mpt))) 455 if (!load_native(ast, module_info, module, module_len, GET_RESOURCE(mpt, obx)))
401 return FALSE; 456 return FALSE;
402 track0_addr = UBYTE(module[2]) + (UBYTE(module[3]) << 8) + 0x1ca; 457 track0_addr = UWORD(module, 2) + 0x1ca;
403 if (UBYTE(module[0x1c6]) + (UBYTE(module[0x1ca]) << 8) != track0_addr) 458 if (UBYTE(module[0x1c6]) + (UBYTE(module[0x1ca]) << 8) != track0_addr)
404 return FALSE; 459 return FALSE;
405 /* Calculate the length of the first track. Address of the second track minus 460 /* Calculate the length of the first track. Address of the second track minus
@@ -409,36 +464,39 @@ FILE_FUNC abool parse_mpt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
409 if (song_len > 0xfe) 464 if (song_len > 0xfe)
410 return FALSE; 465 return FALSE;
411 INIT_ARRAY(global_seen); 466 INIT_ARRAY(global_seen);
412 MODULE_INFO songs = 0; 467 module_info _ songs = 0;
413 for (pos = 0; pos < song_len && MODULE_INFO songs < MAX_SONGS; pos++) { 468 for (pos = 0; pos < song_len && module_info _ songs < ASAP_SONGS_MAX; pos++) {
414 if (!global_seen[pos]) { 469 if (!global_seen[pos]) {
415 MODULE_INFO song_pos[MODULE_INFO songs] = (byte) pos; 470 module_info _ song_pos[module_info _ songs] = CAST(byte) pos;
416 parse_mpt_song(module_info, module, global_seen, song_len, pos); 471 parse_mpt_song(module_info, module, global_seen, song_len, pos);
417 } 472 }
418 } 473 }
419 return MODULE_INFO songs != 0; 474 return module_info _ songs > 0;
420} 475}
421 476
422CONST_LOOKUP(byte, rmt_volume_silent) = { 16, 8, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }; 477CONST_ARRAY(byte, rmt_volume_silent)
478 16, 8, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1
479END_CONST_ARRAY;
423 480
424FILE_FUNC int rmt_instrument_frames(const byte ARRAY module, int instrument, int volume, int volume_frame, abool extra_pokey) 481PRIVATE 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)))
425{ 484{
426 int addr_to_offset = UBYTE(module[2]) + (UBYTE(module[3]) << 8) - 6; 485 V(int, addr_to_offset) = UWORD(module, 2) - 6;
427 int per_frame = module[0xc]; 486 V(int, per_frame) = module[0xc];
428 int player_call; 487 V(int, player_call);
429 int player_calls; 488 V(int, player_calls);
430 int index; 489 V(int, index);
431 int index_end; 490 V(int, index_end);
432 int index_loop; 491 V(int, index_loop);
433 int volume_slide_depth; 492 V(int, volume_slide_depth);
434 int volume_min; 493 V(int, volume_min);
435 abool looping; 494 V(int, volume_slide);
436 int volume_slide; 495 V(abool, silent_loop);
437 abool silent_loop; 496 instrument = UWORD(module, 0xe) - addr_to_offset + (instrument << 1);
438 instrument = UBYTE(module[0xe]) + (UBYTE(module[0xf]) << 8) - addr_to_offset + (instrument << 1);
439 if (module[instrument + 1] == 0) 497 if (module[instrument + 1] == 0)
440 return 0; 498 return 0;
441 instrument = UBYTE(module[instrument]) + (UBYTE(module[instrument + 1]) << 8) - addr_to_offset; 499 instrument = UWORD(module, instrument) - addr_to_offset;
442 player_calls = player_call = volume_frame * per_frame; 500 player_calls = player_call = volume_frame * per_frame;
443 index = UBYTE(module[instrument]) + 1 + player_call * 3; 501 index = UBYTE(module[instrument]) + 1 + player_call * 3;
444 index_end = UBYTE(module[instrument + 2]) + 3; 502 index_end = UBYTE(module[instrument + 2]) + 3;
@@ -447,12 +505,11 @@ FILE_FUNC int rmt_instrument_frames(const byte ARRAY module, int instrument, int
447 return 0; /* error */ 505 return 0; /* error */
448 volume_slide_depth = UBYTE(module[instrument + 6]); 506 volume_slide_depth = UBYTE(module[instrument + 6]);
449 volume_min = UBYTE(module[instrument + 7]); 507 volume_min = UBYTE(module[instrument + 7]);
450 looping = index >= index_end; 508 if (index >= index_end)
451 if (looping)
452 index = (index - index_end) % (index_end - index_loop) + index_loop; 509 index = (index - index_end) % (index_end - index_loop) + index_loop;
453 else { 510 else {
454 do { 511 do {
455 int vol = module[instrument + index]; 512 V(int, vol) = module[instrument + index];
456 if (extra_pokey) 513 if (extra_pokey)
457 vol >>= 4; 514 vol >>= 4;
458 if ((vol & 0xf) >= rmt_volume_silent[volume]) 515 if ((vol & 0xf) >= rmt_volume_silent[volume])
@@ -466,7 +523,7 @@ FILE_FUNC int rmt_instrument_frames(const byte ARRAY module, int instrument, int
466 volume_slide = 128; 523 volume_slide = 128;
467 silent_loop = FALSE; 524 silent_loop = FALSE;
468 for (;;) { 525 for (;;) {
469 int vol; 526 V(int, vol);
470 if (index >= index_end) { 527 if (index >= index_end) {
471 if (silent_loop) 528 if (silent_loop)
472 break; 529 break;
@@ -492,17 +549,18 @@ FILE_FUNC int rmt_instrument_frames(const byte ARRAY module, int instrument, int
492 return player_calls / per_frame; 549 return player_calls / per_frame;
493} 550}
494 551
495FILE_FUNC void parse_rmt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, 552PRIVATE FUNC(void, parse_rmt_song, (
496 abool ARRAY global_seen, int song_len, int pos_shift, int pos) 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)))
497{ 555{
498 int ch; 556 V(int, ch);
499 int addr_to_offset = UBYTE(module[2]) + (UBYTE(module[3]) << 8) - 6; 557 V(int, addr_to_offset) = UWORD(module, 2) - 6;
500 int tempo = UBYTE(module[0xb]); 558 V(int, tempo) = UBYTE(module[0xb]);
501 int frames = 0; 559 V(int, frames) = 0;
502 int song_offset = UBYTE(module[0x14]) + (UBYTE(module[0x15]) << 8) - addr_to_offset; 560 V(int, song_offset) = UWORD(module, 0x14) - addr_to_offset;
503 int pattern_lo_offset = UBYTE(module[0x10]) + (UBYTE(module[0x11]) << 8) - addr_to_offset; 561 V(int, pattern_lo_offset) = UWORD(module, 0x10) - addr_to_offset;
504 int pattern_hi_offset = UBYTE(module[0x12]) + (UBYTE(module[0x13]) << 8) - addr_to_offset; 562 V(int, pattern_hi_offset) = UWORD(module, 0x12) - addr_to_offset;
505 int instrument_frames; 563 V(int, instrument_frames);
506 NEW_ARRAY(byte, seen, 256); 564 NEW_ARRAY(byte, seen, 256);
507 NEW_ARRAY(int, pattern_begin, 8); 565 NEW_ARRAY(int, pattern_begin, 8);
508 NEW_ARRAY(int, pattern_offset, 8); 566 NEW_ARRAY(int, pattern_offset, 8);
@@ -517,11 +575,11 @@ FILE_FUNC void parse_rmt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
517 INIT_ARRAY(volume_value); 575 INIT_ARRAY(volume_value);
518 INIT_ARRAY(volume_frame); 576 INIT_ARRAY(volume_frame);
519 while (pos < song_len) { 577 while (pos < song_len) {
520 int i; 578 V(int, i);
521 int pattern_rows; 579 V(int, pattern_rows);
522 if (seen[pos] != 0) { 580 if (seen[pos] != 0) {
523 if (seen[pos] != SEEN_THIS_CALL) 581 if (seen[pos] != SEEN_THIS_CALL)
524 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 582 module_info _ loops[module_info _ songs] = TRUE;
525 break; 583 break;
526 } 584 }
527 seen[pos] = SEEN_THIS_CALL; 585 seen[pos] = SEEN_THIS_CALL;
@@ -589,37 +647,38 @@ FILE_FUNC void parse_rmt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
589 } 647 }
590 instrument_frames = 0; 648 instrument_frames = 0;
591 for (ch = 0; ch < 1 << pos_shift; ch++) { 649 for (ch = 0; ch < 1 << pos_shift; ch++) {
592 int frame = instrument_frame[ch]; 650 V(int, frame) = instrument_frame[ch];
593 frame += rmt_instrument_frames(module, instrument_no[ch], volume_value[ch], volume_frame[ch] - frame, ch >= 4); 651 frame += rmt_instrument_frames(module, instrument_no[ch], volume_value[ch], volume_frame[ch] - frame, ch >= 4);
594 if (instrument_frames < frame) 652 if (instrument_frames < frame)
595 instrument_frames = frame; 653 instrument_frames = frame;
596 } 654 }
597 if (frames > instrument_frames) { 655 if (frames > instrument_frames) {
598 if (frames - instrument_frames > 100) 656 if (frames - instrument_frames > 100)
599 MODULE_INFO loops[MODULE_INFO songs] = FALSE; 657 module_info _ loops[module_info _ songs] = FALSE;
600 frames = instrument_frames; 658 frames = instrument_frames;
601 } 659 }
602 if (frames > 0) 660 if (frames > 0)
603 set_song_duration(module_info, frames); 661 set_song_duration(module_info, frames);
604} 662}
605 663
606FILE_FUNC abool parse_rmt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 664PRIVATE FUNC(abool, parse_rmt, (
607 const byte ARRAY module, int module_len) 665 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
666 P(CONST BYTEARRAY, module), P(int, module_len)))
608{ 667{
609 int per_frame; 668 V(int, per_frame);
610 int pos_shift; 669 V(int, pos_shift);
611 int song_len; 670 V(int, song_len);
612 int pos; 671 V(int, pos);
613 NEW_ARRAY(abool, global_seen, 256); 672 NEW_ARRAY(abool, global_seen, 256);
614 if (module_len < 0x30 || module[6] != 'R' || module[7] != 'M' 673 if (module_len < 0x30 || module[6] != CHARCODE('R') || module[7] != CHARCODE('M')
615 || module[8] != 'T' || module[0xd] != 1) 674 || module[8] != CHARCODE('T') || module[0xd] != 1)
616 return FALSE; 675 return FALSE;
617 switch ((char) module[9]) { 676 switch (CAST(char) module[9]) {
618 case '4': 677 case CHARCODE('4'):
619 pos_shift = 2; 678 pos_shift = 2;
620 break; 679 break;
621 case '8': 680 case CHARCODE('8'):
622 MODULE_INFO channels = 2; 681 module_info _ channels = 2;
623 pos_shift = 3; 682 pos_shift = 3;
624 break; 683 break;
625 default: 684 default:
@@ -628,45 +687,44 @@ FILE_FUNC abool parse_rmt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
628 per_frame = module[0xc]; 687 per_frame = module[0xc];
629 if (per_frame < 1 || per_frame > 4) 688 if (per_frame < 1 || per_frame > 4)
630 return FALSE; 689 return FALSE;
631 MODULE_INFO type = 'r'; 690 module_info _ type = ASAP_TYPE_RMT;
632 if (!load_native(ast, module_info, module, module_len, 691 if (!load_native(ast, module_info, module, module_len,
633 MODULE_INFO channels == 2 ? GET_OBX(rmt8) : GET_OBX(rmt4))) 692 module_info _ channels == 2 ? GET_RESOURCE(rmt8, obx) : GET_RESOURCE(rmt4, obx)))
634 return FALSE; 693 return FALSE;
635 song_len = UBYTE(module[4]) + (UBYTE(module[5]) << 8) + 1 694 song_len = UWORD(module, 4) + 1 - UWORD(module, 0x14);
636 - UBYTE(module[0x14]) - (UBYTE(module[0x15]) << 8);
637 if (pos_shift == 3 && (song_len & 4) != 0 695 if (pos_shift == 3 && (song_len & 4) != 0
638 && UBYTE(module[6 + UBYTE(module[4]) + (UBYTE(module[5]) << 8) 696 && UBYTE(module[6 + UWORD(module, 4) - UWORD(module, 2) - 3]) == 0xfe)
639 - UBYTE(module[2]) - (UBYTE(module[3]) << 8) - 3]) == 0xfe)
640 song_len += 4; 697 song_len += 4;
641 song_len >>= pos_shift; 698 song_len >>= pos_shift;
642 if (song_len >= 0x100) 699 if (song_len >= 0x100)
643 return FALSE; 700 return FALSE;
644 INIT_ARRAY(global_seen); 701 INIT_ARRAY(global_seen);
645 MODULE_INFO songs = 0; 702 module_info _ songs = 0;
646 for (pos = 0; pos < song_len && MODULE_INFO songs < MAX_SONGS; pos++) { 703 for (pos = 0; pos < song_len && module_info _ songs < ASAP_SONGS_MAX; pos++) {
647 if (!global_seen[pos]) { 704 if (!global_seen[pos]) {
648 MODULE_INFO song_pos[MODULE_INFO songs] = (byte) pos; 705 module_info _ song_pos[module_info _ songs] = CAST(byte) pos;
649 parse_rmt_song(module_info, module, global_seen, song_len, pos_shift, pos); 706 parse_rmt_song(module_info, module, global_seen, song_len, pos_shift, pos);
650 } 707 }
651 } 708 }
652 /* must set fastplay after song durations calculations, so they assume 312 */ 709 /* must set fastplay after song durations calculations, so they assume 312 */
653 MODULE_INFO fastplay = perframe2fastplay[per_frame - 1]; 710 module_info _ fastplay = perframe2fastplay[per_frame - 1];
654 MODULE_INFO player = 0x600; 711 module_info _ player = 0x600;
655 return MODULE_INFO songs != 0; 712 return module_info _ songs > 0;
656} 713}
657 714
658FILE_FUNC void parse_tmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) 715PRIVATE FUNC(void, parse_tmc_song, (
716 P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos)))
659{ 717{
660 int addr_to_offset = UBYTE(module[2]) + (UBYTE(module[3]) << 8) - 6; 718 V(int, addr_to_offset) = UWORD(module, 2) - 6;
661 int tempo = UBYTE(module[0x24]) + 1; 719 V(int, tempo) = UBYTE(module[0x24]) + 1;
662 int frames = 0; 720 V(int, frames) = 0;
663 NEW_ARRAY(int, pattern_offset, 8); 721 NEW_ARRAY(int, pattern_offset, 8);
664 NEW_ARRAY(int, blank_rows, 8); 722 NEW_ARRAY(int, blank_rows, 8);
665 while (UBYTE(module[0x1a6 + 15 + pos]) < 0x80) { 723 while (UBYTE(module[0x1a6 + 15 + pos]) < 0x80) {
666 int ch; 724 V(int, ch);
667 int pattern_rows; 725 V(int, pattern_rows);
668 for (ch = 7; ch >= 0; ch--) { 726 for (ch = 7; ch >= 0; ch--) {
669 int pat = UBYTE(module[0x1a6 + 15 + pos - 2 * ch]); 727 V(int, pat) = UBYTE(module[0x1a6 + 15 + pos - 2 * ch]);
670 pattern_offset[ch] = UBYTE(module[0xa6 + pat]) + (UBYTE(module[0x126 + pat]) << 8) - addr_to_offset; 728 pattern_offset[ch] = UBYTE(module[0xa6 + pat]) + (UBYTE(module[0x126 + pat]) << 8) - addr_to_offset;
671 blank_rows[ch] = 0; 729 blank_rows[ch] = 0;
672 } 730 }
@@ -675,7 +733,7 @@ FILE_FUNC void parse_tmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
675 if (--blank_rows[ch] >= 0) 733 if (--blank_rows[ch] >= 0)
676 continue; 734 continue;
677 for (;;) { 735 for (;;) {
678 int i = UBYTE(module[pattern_offset[ch]++]); 736 V(int, i) = UBYTE(module[pattern_offset[ch]++]);
679 if (i < 0x40) { 737 if (i < 0x40) {
680 pattern_offset[ch]++; 738 pattern_offset[ch]++;
681 break; 739 break;
@@ -710,21 +768,22 @@ FILE_FUNC void parse_tmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
710 pos += 16; 768 pos += 16;
711 } 769 }
712 if (UBYTE(module[0x1a6 + 14 + pos]) < 0x80) 770 if (UBYTE(module[0x1a6 + 14 + pos]) < 0x80)
713 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 771 module_info _ loops[module_info _ songs] = TRUE;
714 set_song_duration(module_info, frames); 772 set_song_duration(module_info, frames);
715} 773}
716 774
717FILE_FUNC abool parse_tmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 775PRIVATE FUNC(abool, parse_tmc, (
718 const byte ARRAY module, int module_len) 776 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
777 P(CONST BYTEARRAY, module), P(int, module_len)))
719{ 778{
720 int i; 779 V(int, i);
721 int last_pos; 780 V(int, last_pos);
722 if (module_len < 0x1d0) 781 if (module_len < 0x1d0)
723 return FALSE; 782 return FALSE;
724 MODULE_INFO type = 't'; 783 module_info _ type = ASAP_TYPE_TMC;
725 if (!load_native(ast, module_info, module, module_len, GET_OBX(tmc))) 784 if (!load_native(ast, module_info, module, module_len, GET_RESOURCE(tmc, obx)))
726 return FALSE; 785 return FALSE;
727 MODULE_INFO channels = 2; 786 module_info _ channels = 2;
728 i = 0; 787 i = 0;
729 /* find first instrument */ 788 /* find first instrument */
730 while (module[0x66 + i] == 0) { 789 while (module[0x66 + i] == 0) {
@@ -732,7 +791,7 @@ FILE_FUNC abool parse_tmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
732 return FALSE; /* no instrument */ 791 return FALSE; /* no instrument */
733 } 792 }
734 last_pos = (UBYTE(module[0x66 + i]) << 8) + UBYTE(module[0x26 + i]) 793 last_pos = (UBYTE(module[0x66 + i]) << 8) + UBYTE(module[0x26 + i])
735 - UBYTE(module[2]) - (UBYTE(module[3]) << 8) - 0x1b0; 794 - UWORD(module, 2) - 0x1b0;
736 if (0x1b5 + last_pos >= module_len) 795 if (0x1b5 + last_pos >= module_len)
737 return FALSE; 796 return FALSE;
738 /* skip trailing jumps */ 797 /* skip trailing jumps */
@@ -741,9 +800,9 @@ FILE_FUNC abool parse_tmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
741 return FALSE; /* no pattern to play */ 800 return FALSE; /* no pattern to play */
742 last_pos -= 16; 801 last_pos -= 16;
743 } while (UBYTE(module[0x1b5 + last_pos]) >= 0x80); 802 } while (UBYTE(module[0x1b5 + last_pos]) >= 0x80);
744 MODULE_INFO songs = 0; 803 module_info _ songs = 0;
745 parse_tmc_song(module_info, module, 0); 804 parse_tmc_song(module_info, module, 0);
746 for (i = 0; i < last_pos && MODULE_INFO songs < MAX_SONGS; i += 16) 805 for (i = 0; i < last_pos && module_info _ songs < ASAP_SONGS_MAX; i += 16)
747 if (UBYTE(module[0x1b5 + i]) >= 0x80) 806 if (UBYTE(module[0x1b5 + i]) >= 0x80)
748 parse_tmc_song(module_info, module, i + 16); 807 parse_tmc_song(module_info, module, i + 16);
749 /* must set fastplay after song durations calculations, so they assume 312 */ 808 /* must set fastplay after song durations calculations, so they assume 312 */
@@ -751,29 +810,30 @@ FILE_FUNC abool parse_tmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
751 if (i < 1 || i > 4) 810 if (i < 1 || i > 4)
752 return FALSE; 811 return FALSE;
753 if (ast != NULL) 812 if (ast != NULL)
754 AST tmc_per_frame = module[0x25]; 813 ast _ tmc_per_frame = module[0x25];
755 MODULE_INFO fastplay = perframe2fastplay[i - 1]; 814 module_info _ fastplay = perframe2fastplay[i - 1];
756 return TRUE; 815 return TRUE;
757} 816}
758 817
759FILE_FUNC void parse_tm2_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) 818PRIVATE FUNC(void, parse_tm2_song, (
819 P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, pos)))
760{ 820{
761 int addr_to_offset = UBYTE(module[2]) + (UBYTE(module[3]) << 8) - 6; 821 V(int, addr_to_offset) = UWORD(module, 2) - 6;
762 int tempo = UBYTE(module[0x24]) + 1; 822 V(int, tempo) = UBYTE(module[0x24]) + 1;
763 int player_calls = 0; 823 V(int, player_calls) = 0;
764 NEW_ARRAY(int, pattern_offset, 8); 824 NEW_ARRAY(int, pattern_offset, 8);
765 NEW_ARRAY(int, blank_rows, 8); 825 NEW_ARRAY(int, blank_rows, 8);
766 for (;;) { 826 for (;;) {
767 int ch; 827 V(int, ch);
768 int pattern_rows = UBYTE(module[0x386 + 16 + pos]); 828 V(int, pattern_rows) = UBYTE(module[0x386 + 16 + pos]);
769 if (pattern_rows == 0) 829 if (pattern_rows == 0)
770 break; 830 break;
771 if (pattern_rows >= 0x80) { 831 if (pattern_rows >= 0x80) {
772 MODULE_INFO loops[MODULE_INFO songs] = TRUE; 832 module_info _ loops[module_info _ songs] = TRUE;
773 break; 833 break;
774 } 834 }
775 for (ch = 7; ch >= 0; ch--) { 835 for (ch = 7; ch >= 0; ch--) {
776 int pat = UBYTE(module[0x386 + 15 + pos - 2 * ch]); 836 V(int, pat) = UBYTE(module[0x386 + 15 + pos - 2 * ch]);
777 pattern_offset[ch] = UBYTE(module[0x106 + pat]) + (UBYTE(module[0x206 + pat]) << 8) - addr_to_offset; 837 pattern_offset[ch] = UBYTE(module[0x106 + pat]) + (UBYTE(module[0x206 + pat]) << 8) - addr_to_offset;
778 blank_rows[ch] = 0; 838 blank_rows[ch] = 0;
779 } 839 }
@@ -782,7 +842,7 @@ FILE_FUNC void parse_tm2_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
782 if (--blank_rows[ch] >= 0) 842 if (--blank_rows[ch] >= 0)
783 continue; 843 continue;
784 for (;;) { 844 for (;;) {
785 int i = UBYTE(module[pattern_offset[ch]++]); 845 V(int, i) = UBYTE(module[pattern_offset[ch]++]);
786 if (i == 0) { 846 if (i == 0) {
787 pattern_offset[ch]++; 847 pattern_offset[ch]++;
788 break; 848 break;
@@ -829,36 +889,37 @@ FILE_FUNC void parse_tm2_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY
829 set_song_duration(module_info, player_calls); 889 set_song_duration(module_info, player_calls);
830} 890}
831 891
832FILE_FUNC abool parse_tm2(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 892PRIVATE FUNC(abool, parse_tm2, (
833 const byte ARRAY module, int module_len) 893 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
894 P(CONST BYTEARRAY, module), P(int, module_len)))
834{ 895{
835 int i; 896 V(int, i);
836 int last_pos; 897 V(int, last_pos);
837 int c; 898 V(int, c);
838 if (module_len < 0x3a4) 899 if (module_len < 0x3a4)
839 return FALSE; 900 return FALSE;
840 MODULE_INFO type = 'T'; 901 module_info _ type = ASAP_TYPE_TM2;
841 if (!load_native(ast, module_info, module, module_len, GET_OBX(tm2))) 902 if (!load_native(ast, module_info, module, module_len, GET_RESOURCE(tm2, obx)))
842 return FALSE; 903 return FALSE;
843 i = module[0x25]; 904 i = module[0x25];
844 if (i < 1 || i > 4) 905 if (i < 1 || i > 4)
845 return FALSE; 906 return FALSE;
846 MODULE_INFO fastplay = perframe2fastplay[i - 1]; 907 module_info _ fastplay = perframe2fastplay[i - 1];
847 MODULE_INFO player = 0x500; 908 module_info _ player = 0x500;
848 if (module[0x1f] != 0) 909 if (module[0x1f] != 0)
849 MODULE_INFO channels = 2; 910 module_info _ channels = 2;
850 last_pos = 0xffff; 911 last_pos = 0xffff;
851 for (i = 0; i < 0x80; i++) { 912 for (i = 0; i < 0x80; i++) {
852 int instr_addr = UBYTE(module[0x86 + i]) + (UBYTE(module[0x306 + i]) << 8); 913 V(int, instr_addr) = UBYTE(module[0x86 + i]) + (UBYTE(module[0x306 + i]) << 8);
853 if (instr_addr != 0 && instr_addr < last_pos) 914 if (instr_addr != 0 && instr_addr < last_pos)
854 last_pos = instr_addr; 915 last_pos = instr_addr;
855 } 916 }
856 for (i = 0; i < 0x100; i++) { 917 for (i = 0; i < 0x100; i++) {
857 int pattern_addr = UBYTE(module[0x106 + i]) + (UBYTE(module[0x206 + i]) << 8); 918 V(int, pattern_addr) = UBYTE(module[0x106 + i]) + (UBYTE(module[0x206 + i]) << 8);
858 if (pattern_addr != 0 && pattern_addr < last_pos) 919 if (pattern_addr != 0 && pattern_addr < last_pos)
859 last_pos = pattern_addr; 920 last_pos = pattern_addr;
860 } 921 }
861 last_pos -= UBYTE(module[2]) + (UBYTE(module[3]) << 8) + 0x380; 922 last_pos -= UWORD(module, 2) + 0x380;
862 if (0x386 + last_pos >= module_len) 923 if (0x386 + last_pos >= module_len)
863 return FALSE; 924 return FALSE;
864 /* skip trailing stop/jump commands */ 925 /* skip trailing stop/jump commands */
@@ -868,9 +929,9 @@ FILE_FUNC abool parse_tm2(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
868 last_pos -= 17; 929 last_pos -= 17;
869 c = UBYTE(module[0x386 + 16 + last_pos]); 930 c = UBYTE(module[0x386 + 16 + last_pos]);
870 } while (c == 0 || c >= 0x80); 931 } while (c == 0 || c >= 0x80);
871 MODULE_INFO songs = 0; 932 module_info _ songs = 0;
872 parse_tm2_song(module_info, module, 0); 933 parse_tm2_song(module_info, module, 0);
873 for (i = 0; i < last_pos && MODULE_INFO songs < MAX_SONGS; i += 17) { 934 for (i = 0; i < last_pos && module_info _ songs < ASAP_SONGS_MAX; i += 17) {
874 c = UBYTE(module[0x386 + 16 + i]); 935 c = UBYTE(module[0x386 + 16 + i]);
875 if (c == 0 || c >= 0x80) 936 if (c == 0 || c >= 0x80)
876 parse_tm2_song(module_info, module, i + 17); 937 parse_tm2_song(module_info, module, i + 17);
@@ -878,280 +939,262 @@ FILE_FUNC abool parse_tm2(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
878 return TRUE; 939 return TRUE;
879} 940}
880 941
881#if !defined(JAVA) && !defined(CSHARP) 942#endif /* ASAP_ONLY_SAP */
882
883static abool parse_hex(int *retval, const char *p)
884{
885 int r = 0;
886 do {
887 char c = *p;
888 if (r > 0xfff)
889 return FALSE;
890 r <<= 4;
891 if (c >= '0' && c <= '9')
892 r += c - '0';
893 else if (c >= 'A' && c <= 'F')
894 r += c - 'A' + 10;
895 else if (c >= 'a' && c <= 'f')
896 r += c - 'a' + 10;
897 else
898 return FALSE;
899 } while (*++p != '\0');
900 *retval = r;
901 return TRUE;
902}
903 943
904static abool parse_dec(int *retval, const char *p, int minval, int maxval) 944PRIVATE FUNC(abool, has_string_at, (P(CONST BYTEARRAY, module), P(int, module_index), P(STRING, s)))
905{ 945{
906 int r = 0; 946 V(int, i);
907 do { 947 V(int, n) = strlen(s);
908 char c = *p; 948 for (i = 0; i < n; i++)
909 if (c >= '0' && c <= '9') 949 if (module[module_index + i] != CHARCODEAT(s, i))
910 r = 10 * r + c - '0';
911 else
912 return FALSE; 950 return FALSE;
913 if (r > maxval)
914 return FALSE;
915 } while (*++p != '\0');
916 if (r < minval)
917 return FALSE;
918 *retval = r;
919 return TRUE; 951 return TRUE;
920} 952}
921 953
922static abool parse_text(char *retval, const char *p) 954PRIVATE FUNC(STRING, parse_text, (P(OUT_STRING, dest), P(CONST BYTEARRAY, module), P(int, module_index)))
923{ 955{
924 int i; 956 V(int, i);
925 if (*p != '"') 957 if (module[module_index] != CHARCODE('"'))
926 return FALSE; 958 return NULL;
927 p++; 959 if (has_string_at(module, module_index + 1, "<?>\""))
928 if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"') 960 return dest;
929 return TRUE; 961 for (i = 0; ; i++) {
930 i = 0; 962 V(int, c) = module[module_index + 1 + i];
931 while (*p != '"') { 963 if (c == CHARCODE('"'))
932 if (i >= 127) 964 break;
933 return FALSE; 965 if (c < 32 || c >= 127)
934 if (*p == '\0') 966 return NULL;
935 return FALSE;
936 retval[i++] = *p++;
937 } 967 }
938 retval[i] = '\0'; 968 BYTES_TO_STRING(dest, module, module_index + 1, i);
939 return TRUE; 969 return dest;
940} 970}
941 971
942int ASAP_ParseDuration(const char *s) 972PRIVATE FUNC(int, parse_dec, (P(CONST BYTEARRAY, module), P(int, module_index), P(int, maxval)))
943{ 973{
944 int r; 974 V(int, r);
945 if (*s < '0' || *s > '9') 975 if (module[module_index] == 0xd)
946 return -1; 976 return -1;
947 r = *s++ - '0'; 977 for (r = 0;;) {
948 if (*s >= '0' && *s <= '9') 978 V(int, c) = module[module_index++];
949 r = 10 * r + *s++ - '0'; 979 if (c == 0xd)
950 if (*s == ':') { 980 break;
951 s++; 981 if (c < CHARCODE('0') || c > CHARCODE('9'))
952 if (*s < '0' || *s > '5')
953 return -1; 982 return -1;
954 r = 60 * r + (*s++ - '0') * 10; 983 r = 10 * r + c - 48;
955 if (*s < '0' || *s > '9') 984 if (r > maxval)
956 return -1; 985 return -1;
957 r += *s++ - '0';
958 } 986 }
959 r *= 1000;
960 if (*s != '.')
961 return r;
962 s++;
963 if (*s < '0' || *s > '9')
964 return r;
965 r += 100 * (*s++ - '0');
966 if (*s < '0' || *s > '9')
967 return r;
968 r += 10 * (*s++ - '0');
969 if (*s < '0' || *s > '9')
970 return r;
971 r += *s - '0';
972 return r; 987 return r;
973} 988}
974 989
975static char *two_digits(char *s, int x) 990PRIVATE FUNC(int, parse_hex, (P(CONST BYTEARRAY, module), P(int, module_index)))
976{ 991{
977 s[0] = '0' + x / 10; 992 V(int, r);
978 s[1] = '0' + x % 10; 993 if (module[module_index] == 0xd)
979 return s + 2; 994 return -1;
995 for (r = 0;;) {
996 V(int, c) = module[module_index++];
997 if (c == 0xd)
998 break;
999 if (r > 0xfff)
1000 return -1;
1001 r <<= 4;
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;
1008 else
1009 return -1;
1010 }
1011 return r;
980} 1012}
981 1013
982void ASAP_DurationToString(char *s, int duration) 1014FUNC(int, ASAP_ParseDuration, (P(STRING, s)))
983{ 1015{
984 if (duration >= 0) { 1016 V(int, i) = 0;
985 int seconds = duration / 1000; 1017 V(int, r);
986 int minutes = seconds / 60; 1018 V(int, d);
987 s = two_digits(s, minutes); 1019 V(int, n) = strlen(s);
988 *s++ = ':'; 1020#define PARSE_DIGIT(maxdig, retifnot) \
989 s = two_digits(s, seconds % 60); 1021 if (i >= n) \
990 duration %= 1000; 1022 return retifnot; \
991 if (duration != 0) { 1023 d = CHARCODEAT(s, i) - 48; \
992 *s++ = '.'; 1024 if (d < 0 || d > maxdig) \
993 s = two_digits(s, duration / 10); 1025 return -1; \
994 duration %= 10; 1026 i++;
995 if (duration != 0) 1027
996 *s++ = '0' + duration; 1028 PARSE_DIGIT(9, -1);
1029 r = d;
1030 if (i < n) {
1031 d = CHARCODEAT(s, i) - 48;
1032 if (d >= 0 && d <= 9) {
1033 i++;
1034 r = 10 * r + d;
1035 }
1036 if (i < n && CHARAT(s, i) == ':') {
1037 i++;
1038 PARSE_DIGIT(5, -1);
1039 r = (6 * r + d) * 10;
1040 PARSE_DIGIT(9, -1);
1041 r += d;
997 } 1042 }
998 } 1043 }
999 *s = '\0'; 1044 r *= 1000;
1045 if (i >= n)
1046 return r;
1047 if (CHARAT(s, i) != '.')
1048 return -1;
1049 i++;
1050 PARSE_DIGIT(9, -1);
1051 r += 100 * d;
1052 PARSE_DIGIT(9, r);
1053 r += 10 * d;
1054 PARSE_DIGIT(9, r);
1055 r += d;
1056 return r;
1000} 1057}
1001 1058
1002#endif /* !defined(JAVA) && !defined(CSHARP) */ 1059PRIVATE FUNC(abool, parse_sap_header, (
1003 1060 P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, module_len)))
1004FILE_FUNC abool parse_sap_header(ASAP_ModuleInfo PTR module_info,
1005 const byte ARRAY module, int module_len)
1006{ 1061{
1007 int module_index = 0; 1062 V(int, module_index);
1008 abool sap_signature = FALSE; 1063 V(int, type) = 0;
1009 int duration_index = 0; 1064 V(int, duration_index) = 0;
1010 for (;;) { 1065 if (!has_string_at(module, 0, "SAP\r\n"))
1011 NEW_ARRAY(char, line, 256); 1066 return FALSE;
1012 int i; 1067 module_index = 5;
1013#if !defined(JAVA) && !defined(CSHARP) 1068 while (UBYTE(module[module_index]) != 0xff) {
1014 char *p;
1015#endif
1016 if (module_index + 8 >= module_len) 1069 if (module_index + 8 >= module_len)
1017 return FALSE; 1070 return FALSE;
1018 if (UBYTE(module[module_index]) == 0xff) 1071#define TAG_IS(s) has_string_at(module, module_index, s)
1019 break; 1072#ifdef C
1020 i = 0; 1073#define SET_TEXT(v, i) if (parse_text(v, module, module_index + i) == NULL) return FALSE
1021 while (module[module_index] != 0x0d) { 1074#else
1022 line[i++] = (char) module[module_index++]; 1075#define SET_TEXT(v, i) v = parse_text(v, module, module_index + i); if (v == NULL) return FALSE
1023 if (module_index >= module_len || (unsigned)i >= sizeof(line) - 1) 1076#endif
1024 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);
1025 } 1081 }
1026 if (++module_index >= module_len || module[module_index++] != 0x0a) 1082 else if (TAG_IS("NAME ")) {
1027 return FALSE; 1083 SET_TEXT(module_info _ name, 5);
1028 1084 }
1029#ifdef JAVA 1085 else if (TAG_IS("DATE ")) {
1030 String tag = new String(line, 0, i); 1086 SET_TEXT(module_info _ date, 5);
1031 String arg = null; 1087 }
1032 i = tag.indexOf(' '); 1088 else if (TAG_IS("SONGS ")) {
1033 if (i >= 0) { 1089 SET_DEC(module_info _ songs, 6, 1, ASAP_SONGS_MAX);
1034 arg = tag.substring(i + 1); 1090 }
1035 tag = tag.substring(0, i); 1091 else if (TAG_IS("DEFSONG ")) {
1036 } 1092 SET_DEC(module_info _ default_song, 8, 0, ASAP_SONGS_MAX - 1);
1037#define TAG_IS(t) tag.equals(t) 1093 }
1038#define CHAR_ARG arg.charAt(0) 1094 else if (TAG_IS("STEREO\r"))
1039#define SET_HEX(v) v = Integer.parseInt(arg, 16) 1095 module_info _ channels = 2;
1040#define SET_DEC(v, min, max) do { v = Integer.parseInt(arg); if (v < min || v > max) return FALSE; } while (FALSE) 1096 else if (TAG_IS("TIME ")) {
1041#define SET_TEXT(v) v = arg.substring(1, arg.length() - 1) 1097 V(int, i);
1042#define DURATION_ARG parseDuration(arg) 1098#ifdef C
1043#define ARG_CONTAINS(t) (arg.indexOf(t) >= 0) 1099 char s[ASAP_DURATION_CHARS];
1044#elif defined(CSHARP)
1045 string tag = new string(line, 0, i);
1046 string arg = null;
1047 i = tag.IndexOf(' ');
1048 if (i >= 0) {
1049 arg = tag.Substring(i + 1);
1050 tag = tag.Substring(0, i);
1051 }
1052#define TAG_IS(t) tag == t
1053#define CHAR_ARG arg[0]
1054#define SET_HEX(v) v = int.Parse(arg, System.Globalization.NumberStyles.HexNumber)
1055#define SET_DEC(v, min, max) do { v = int.Parse(arg); if (v < min || v > max) return FALSE; } while (FALSE)
1056#define SET_TEXT(v) v = arg.Substring(1, arg.Length - 1)
1057#define DURATION_ARG ParseDuration(arg)
1058#define ARG_CONTAINS(t) (arg.IndexOf(t) >= 0)
1059#else 1100#else
1060 line[i] = '\0'; 1101 V(STRING, s);
1061 for (p = line; *p != '\0'; p++) { 1102#endif
1062 if (*p == ' ') { 1103 module_index += 5;
1063 *p++ = '\0'; 1104 for (i = 0; module[module_index + i] != 0xd; i++);
1064 break; 1105 if (i > 5 && has_string_at(module, module_index + i - 5, " LOOP")) {
1106 module_info _ loops[duration_index] = TRUE;
1107 i -= 5;
1065 } 1108 }
1066 } 1109#ifdef C
1067#define TAG_IS(t) (strcmp(line, t) == 0) 1110 if (i >= ASAP_DURATION_CHARS)
1068#define CHAR_ARG *p 1111 return FALSE;
1069#define SET_HEX(v) do { if (!parse_hex(&v, p)) return FALSE; } while (FALSE)
1070#define SET_DEC(v, min, max) do { if (!parse_dec(&v, p, min, max)) return FALSE; } while (FALSE)
1071#define SET_TEXT(v) do { if (!parse_text(v, p)) return FALSE; } while (FALSE)
1072#define DURATION_ARG ASAP_ParseDuration(p)
1073#define ARG_CONTAINS(t) (strstr(p, t) != NULL)
1074#endif 1112#endif
1113 BYTES_TO_STRING(s, module, module_index, i);
1114 i = ASAP_ParseDuration(s);
1115 if (i < 0 || duration_index >= ASAP_SONGS_MAX)
1116 return FALSE;
1117 module_info _ durations[duration_index++] = i;
1118 }
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);
1123 }
1124 else if (TAG_IS("MUSIC ")) {
1125 SET_HEX(module_info _ music, 6);
1126 }
1127 else if (TAG_IS("INIT ")) {
1128 SET_HEX(module_info _ init, 5);
1129 }
1130 else if (TAG_IS("PLAYER ")) {
1131 SET_HEX(module_info _ player, 7);
1132 }
1133 else if (TAG_IS("COVOX ")) {
1134 SET_HEX(module_info _ covox_addr, 6);
1135 if (module_info _ covox_addr != 0xd600)
1136 return FALSE;
1137 module_info _ channels = 2;
1138 }
1075 1139
1076 if (TAG_IS("SAP")) 1140 while (module[module_index++] != 0x0d) {
1077 sap_signature = TRUE; 1141 if (module_index >= module_len)
1078 if (!sap_signature)
1079 return FALSE;
1080 if (TAG_IS("AUTHOR"))
1081 SET_TEXT(MODULE_INFO author);
1082 else if (TAG_IS("NAME"))
1083 SET_TEXT(MODULE_INFO name);
1084 else if (TAG_IS("DATE"))
1085 SET_TEXT(MODULE_INFO date);
1086 else if (TAG_IS("SONGS"))
1087 SET_DEC(MODULE_INFO songs, 1, MAX_SONGS);
1088 else if (TAG_IS("DEFSONG"))
1089 SET_DEC(MODULE_INFO default_song, 0, MAX_SONGS - 1);
1090 else if (TAG_IS("STEREO"))
1091 MODULE_INFO channels = 2;
1092 else if (TAG_IS("TIME")) {
1093 int duration = DURATION_ARG;
1094 if (duration < 0 || duration_index >= MAX_SONGS)
1095 return FALSE; 1142 return FALSE;
1096 MODULE_INFO durations[duration_index] = duration; 1143 }
1097 if (ARG_CONTAINS("LOOP")) 1144 if (module[module_index++] != 0x0a)
1098 MODULE_INFO loops[duration_index] = TRUE; 1145 return FALSE;
1099 duration_index++;
1100 }
1101 else if (TAG_IS("TYPE"))
1102 MODULE_INFO type = CHAR_ARG;
1103 else if (TAG_IS("FASTPLAY"))
1104 SET_DEC(MODULE_INFO fastplay, 1, 312);
1105 else if (TAG_IS("MUSIC"))
1106 SET_HEX(MODULE_INFO music);
1107 else if (TAG_IS("INIT"))
1108 SET_HEX(MODULE_INFO init);
1109 else if (TAG_IS("PLAYER"))
1110 SET_HEX(MODULE_INFO player);
1111 } 1146 }
1112 if (MODULE_INFO default_song >= MODULE_INFO songs) 1147 if (module_info _ default_song >= module_info _ songs)
1113 return FALSE; 1148 return FALSE;
1114 switch (MODULE_INFO type) { 1149 switch (type) {
1115 case 'B': 1150 case CHARCODE('B'):
1116 case 'D': 1151 if (module_info _ player < 0 || module_info _ init < 0)
1117 if (MODULE_INFO player < 0 || MODULE_INFO init < 0) 1152 return FALSE;
1153 module_info _ type = ASAP_TYPE_SAP_B;
1154 break;
1155 case CHARCODE('C'):
1156 if (module_info _ player < 0 || module_info _ music < 0)
1118 return FALSE; 1157 return FALSE;
1158 module_info _ type = ASAP_TYPE_SAP_C;
1119 break; 1159 break;
1120 case 'C': 1160 case CHARCODE('D'):
1121 if (MODULE_INFO player < 0 || MODULE_INFO music < 0) 1161 if (module_info _ init < 0)
1122 return FALSE; 1162 return FALSE;
1163 module_info _ type = ASAP_TYPE_SAP_D;
1123 break; 1164 break;
1124 case 'S': 1165 case CHARCODE('S'):
1125 if (MODULE_INFO init < 0) 1166 if (module_info _ init < 0)
1126 return FALSE; 1167 return FALSE;
1127 MODULE_INFO fastplay = 78; 1168 module_info _ type = ASAP_TYPE_SAP_S;
1169 module_info _ fastplay = 78;
1128 break; 1170 break;
1129 default: 1171 default:
1130 return FALSE; 1172 return FALSE;
1131 } 1173 }
1132 if (UBYTE(module[module_index + 1]) != 0xff) 1174 if (UBYTE(module[module_index + 1]) != 0xff)
1133 return FALSE; 1175 return FALSE;
1134 MODULE_INFO header_len = module_index; 1176 module_info _ header_len = module_index;
1135 return TRUE; 1177 return TRUE;
1136} 1178}
1137 1179
1138FILE_FUNC abool parse_sap(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 1180PRIVATE FUNC(abool, parse_sap, (
1139 const byte ARRAY module, int module_len) 1181 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
1182 P(CONST BYTEARRAY, module), P(int, module_len)))
1140{ 1183{
1141 int module_index; 1184 V(int, module_index);
1142 if (!parse_sap_header(module_info, module, module_len)) 1185 if (!parse_sap_header(module_info, module, module_len))
1143 return FALSE; 1186 return FALSE;
1144 if (ast == NULL) 1187 if (ast == NULL)
1145 return TRUE; 1188 return TRUE;
1146 ZERO_ARRAY(AST memory); 1189 ZERO_ARRAY(ast _ memory);
1147 module_index = MODULE_INFO header_len + 2; 1190 module_index = module_info _ header_len + 2;
1148 while (module_index + 5 <= module_len) { 1191 while (module_index + 5 <= module_len) {
1149 int start_addr = UBYTE(module[module_index]) + (UBYTE(module[module_index + 1]) << 8); 1192 V(int, start_addr) = UWORD(module, module_index);
1150 int block_len = UBYTE(module[module_index + 2]) + (UBYTE(module[module_index + 3]) << 8) + 1 - start_addr; 1193 V(int, block_len) = UWORD(module, module_index + 2) + 1 - start_addr;
1151 if (block_len <= 0 || module_index + block_len > module_len) 1194 if (block_len <= 0 || module_index + block_len > module_len)
1152 return FALSE; 1195 return FALSE;
1153 module_index += 4; 1196 module_index += 4;
1154 COPY_ARRAY(AST memory, start_addr, module, module_index, block_len); 1197 COPY_ARRAY(ast _ memory, start_addr, module, module_index, block_len);
1155 module_index += block_len; 1198 module_index += block_len;
1156 if (module_index == module_len) 1199 if (module_index == module_len)
1157 return TRUE; 1200 return TRUE;
@@ -1162,387 +1205,452 @@ FILE_FUNC abool parse_sap(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info,
1162 return FALSE; 1205 return FALSE;
1163} 1206}
1164 1207
1165#define ASAP_EXT(c1, c2, c3) (((c1) + ((c2) << 8) + ((c3) << 16)) | 0x202020) 1208#define ASAP_EXT(c1, c2, c3) ((CHARCODE(c1) + (CHARCODE(c2) << 8) + (CHARCODE(c3) << 16)) | 0x202020)
1166 1209
1167FILE_FUNC int get_packed_ext(STRING filename) 1210PRIVATE FUNC(int, get_packed_ext, (P(STRING, filename)))
1168{ 1211{
1169#ifdef JAVA 1212 V(int, i) = strlen(filename);
1170 int i = filename.length(); 1213 V(int, ext) = 0;
1171 int ext = 0;
1172 while (--i > 0) {
1173 if (filename.charAt(i) == '.')
1174 return ext | 0x202020;
1175 ext = (ext << 8) + filename.charAt(i);
1176 }
1177 return 0;
1178#elif defined(CSHARP)
1179 int i = filename.Length;
1180 int ext = 0;
1181 while (--i > 0) { 1214 while (--i > 0) {
1182 if (filename[i] == '.') 1215 V(char, c) = CHARAT(filename, i);
1216 if (c <= ' ' || c > 'z')
1217 return 0;
1218 if (c == '.')
1183 return ext | 0x202020; 1219 return ext | 0x202020;
1184 ext = (ext << 8) + filename[i]; 1220 ext = (ext << 8) + CHARCODE(c);
1185 } 1221 }
1186 return 0; 1222 return 0;
1187#else
1188 const char *p;
1189 int ext;
1190 for (p = filename; *p != '\0'; p++);
1191 ext = 0;
1192 for (;;) {
1193 if (--p <= filename || *p <= ' ')
1194 return 0; /* no filename extension or invalid character */
1195 if (*p == '.')
1196 return ext | 0x202020;
1197 ext = (ext << 8) + (*p & 0xff);
1198 }
1199#endif
1200} 1223}
1201 1224
1202FILE_FUNC abool is_our_ext(int ext) 1225PRIVATE FUNC(abool, is_our_ext, (P(int, ext)))
1203{ 1226{
1204 switch (ext) { 1227 switch (ext) {
1228 case ASAP_EXT('S', 'A', 'P'):
1229#ifndef ASAP_ONLY_SAP
1205 case ASAP_EXT('C', 'M', 'C'): 1230 case ASAP_EXT('C', 'M', 'C'):
1231 case ASAP_EXT('C', 'M', '3'):
1206 case ASAP_EXT('C', 'M', 'R'): 1232 case ASAP_EXT('C', 'M', 'R'):
1233 case ASAP_EXT('C', 'M', 'S'):
1207 case ASAP_EXT('D', 'M', 'C'): 1234 case ASAP_EXT('D', 'M', 'C'):
1208 case ASAP_EXT('M', 'P', 'D'): 1235 case ASAP_EXT('D', 'L', 'T'):
1209 case ASAP_EXT('M', 'P', 'T'): 1236 case ASAP_EXT('M', 'P', 'T'):
1237 case ASAP_EXT('M', 'P', 'D'):
1210 case ASAP_EXT('R', 'M', 'T'): 1238 case ASAP_EXT('R', 'M', 'T'):
1211 case ASAP_EXT('S', 'A', 'P'):
1212 case ASAP_EXT('T', 'M', '2'):
1213 case ASAP_EXT('T', 'M', '8'):
1214 case ASAP_EXT('T', 'M', 'C'): 1239 case ASAP_EXT('T', 'M', 'C'):
1240 case ASAP_EXT('T', 'M', '8'):
1241 case ASAP_EXT('T', 'M', '2'):
1242#endif
1215 return TRUE; 1243 return TRUE;
1216 default: 1244 default:
1217 return FALSE; 1245 return FALSE;
1218 } 1246 }
1219} 1247}
1220 1248
1221ASAP_FUNC abool ASAP_IsOurFile(STRING filename) 1249FUNC(abool, ASAP_IsOurFile, (P(STRING, filename)))
1222{ 1250{
1223 int ext = get_packed_ext(filename); 1251 V(int, ext) = get_packed_ext(filename);
1224 return is_our_ext(ext); 1252 return is_our_ext(ext);
1225} 1253}
1226 1254
1227ASAP_FUNC abool ASAP_IsOurExt(STRING ext) 1255FUNC(abool, ASAP_IsOurExt, (P(STRING, ext)))
1228{ 1256{
1229#ifdef JAVA 1257 return strlen(ext) == 3
1230 return ext.length() == 3 1258 && is_our_ext(ASAP_EXT(CHARAT(ext, 0), CHARAT(ext, 1), CHARAT(ext, 2)));
1231 && is_our_ext(ASAP_EXT(ext.charAt(0), ext.charAt(1), ext.charAt(2)));
1232#else
1233 return ext[0] > ' ' && ext[1] > ' ' && ext[2] > ' ' && ext[3] == '\0'
1234 && is_our_ext(ASAP_EXT(ext[0], ext[1], ext[2]));
1235#endif
1236} 1259}
1237 1260
1238FILE_FUNC abool parse_file(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, 1261PRIVATE FUNC(abool, parse_file, (
1239 STRING filename, const byte ARRAY module, int module_len) 1262 P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info),
1263 P(STRING, filename), P(CONST BYTEARRAY, module), P(int, module_len)))
1240{ 1264{
1241 int i; 1265 V(int, i);
1242#ifdef JAVA 1266 V(int, len) = strlen(filename);
1243 int basename = 0; 1267 V(int, basename) = 0;
1244 int ext = -1; 1268 V(int, ext) = -1;
1245 for (i = 0; i < filename.length(); i++) { 1269 for (i = 0; i < len; i++) {
1246 int c = filename.charAt(i); 1270 V(char, c) = CHARAT(filename, i);
1247 if (c == '/' || c == '\\') 1271 if (c == '/' || c == '\\') {
1248 basename = i + 1;
1249 else if (c == '.')
1250 ext = i;
1251 }
1252 if (ext < 0)
1253 ext = i;
1254 module_info.author = "";
1255 module_info.name = filename.substring(basename, ext);
1256 module_info.date = "";
1257#elif defined(CSHARP)
1258 int basename = 0;
1259 int ext = -1;
1260 for (i = 0; i < filename.Length; i++) {
1261 int c = filename[i];
1262 if (c == '/' || c == '\\')
1263 basename = i + 1; 1272 basename = i + 1;
1273 ext = -1;
1274 }
1264 else if (c == '.') 1275 else if (c == '.')
1265 ext = i; 1276 ext = i;
1266 } 1277 }
1267 if (ext < 0) 1278 if (ext < 0)
1268 ext = i; 1279 return FALSE;
1269 module_info.author = string.Empty; 1280 EMPTY_STRING(module_info _ author);
1270 module_info.name = filename.Substring(basename, ext - basename); 1281 SUBSTRING(module_info _ name, filename, basename, ext - basename);
1271 module_info.date = string.Empty; 1282 EMPTY_STRING(module_info _ date);
1272#else 1283 module_info _ channels = 1;
1273 const char *p; 1284 module_info _ songs = 1;
1274 const char *basename = filename; 1285 module_info _ default_song = 0;
1275 const char *ext = NULL; 1286 for (i = 0; i < ASAP_SONGS_MAX; i++) {
1276 for (p = filename; *p != '\0'; p++) { 1287 module_info _ durations[i] = -1;
1277 if (*p == '/' || *p == '\\') 1288 module_info _ loops[i] = FALSE;
1278 basename = p + 1;
1279 else if (*p == '.')
1280 ext = p;
1281 }
1282 if (ext == NULL)
1283 ext = p;
1284 module_info->author[0] = '\0';
1285 i = ext - basename;
1286 memcpy(module_info->name, basename, i);
1287 module_info->name[i] = '\0';
1288 module_info->date[0] = '\0';
1289#endif
1290 MODULE_INFO channels = 1;
1291 MODULE_INFO songs = 1;
1292 MODULE_INFO default_song = 0;
1293 for (i = 0; i < MAX_SONGS; i++) {
1294 MODULE_INFO durations[i] = -1;
1295 MODULE_INFO loops[i] = FALSE;
1296 } 1289 }
1297 MODULE_INFO type = '?'; 1290 module_info _ fastplay = 312;
1298 MODULE_INFO fastplay = 312; 1291 module_info _ music = -1;
1299 MODULE_INFO music = -1; 1292 module_info _ init = -1;
1300 MODULE_INFO init = -1; 1293 module_info _ player = -1;
1301 MODULE_INFO player = -1; 1294 module_info _ covox_addr = -1;
1302 switch (get_packed_ext(filename)) { 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
1303 case ASAP_EXT('C', 'M', 'C'): 1299 case ASAP_EXT('C', 'M', 'C'):
1304 return parse_cmc(ast, module_info, module, module_len, FALSE); 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));
1305 case ASAP_EXT('C', 'M', 'R'): 1303 case ASAP_EXT('C', 'M', 'R'):
1306 return parse_cmc(ast, module_info, module, module_len, TRUE); 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));
1307 case ASAP_EXT('D', 'M', 'C'): 1308 case ASAP_EXT('D', 'M', 'C'):
1308 MODULE_INFO fastplay = 156; 1309 module_info _ fastplay = 156;
1309 return parse_cmc(ast, module_info, module, module_len, FALSE); 1310 return parse_cmc(ast, module_info, module, module_len, ASAP_TYPE_CMC, GET_RESOURCE(cmc, obx));
1310 case ASAP_EXT('M', 'P', 'D'): 1311 case ASAP_EXT('D', 'L', 'T'):
1311 MODULE_INFO fastplay = 156; 1312 return parse_dlt(ast, module_info, module, module_len);
1312 return parse_mpt(ast, module_info, module, module_len);
1313 case ASAP_EXT('M', 'P', 'T'): 1313 case ASAP_EXT('M', 'P', 'T'):
1314 return parse_mpt(ast, module_info, module, module_len); 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);
1315 case ASAP_EXT('R', 'M', 'T'): 1318 case ASAP_EXT('R', 'M', 'T'):
1316 return parse_rmt(ast, module_info, module, module_len); 1319 return parse_rmt(ast, module_info, module, module_len);
1317 case ASAP_EXT('S', 'A', 'P'):
1318 return parse_sap(ast, module_info, module, module_len);
1319 case ASAP_EXT('T', 'M', '2'):
1320 return parse_tm2(ast, module_info, module, module_len);
1321 case ASAP_EXT('T', 'M', '8'):
1322 case ASAP_EXT('T', 'M', 'C'): 1320 case ASAP_EXT('T', 'M', 'C'):
1321 case ASAP_EXT('T', 'M', '8'):
1323 return parse_tmc(ast, module_info, module, module_len); 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);
1325#endif
1324 default: 1326 default:
1325 return FALSE; 1327 return FALSE;
1326 } 1328 }
1327} 1329}
1328 1330
1329ASAP_FUNC abool ASAP_GetModuleInfo(ASAP_ModuleInfo PTR module_info, STRING filename, 1331FUNC(abool, ASAP_GetModuleInfo, (
1330 const byte ARRAY module, int module_len) 1332 P(ASAP_ModuleInfo PTR, module_info), P(STRING, filename),
1333 P(CONST BYTEARRAY, module), P(int, module_len)))
1331{ 1334{
1332 return parse_file(NULL, module_info, filename, module, module_len); 1335 return parse_file(NULL, module_info, filename, module, module_len);
1333} 1336}
1334 1337
1335ASAP_FUNC abool ASAP_Load(ASAP_State PTR ast, STRING filename, 1338FUNC(abool, ASAP_Load, (
1336 const byte ARRAY module, int module_len) 1339 P(ASAP_State PTR, ast), P(STRING, filename),
1340 P(CONST BYTEARRAY, module), P(int, module_len)))
1337{ 1341{
1338 AST silence_cycles = 0; 1342 ast _ silence_cycles = 0;
1339 return parse_file(ast, ADDRESSOF AST module_info, filename, module, module_len); 1343 return parse_file(ast, ADDRESSOF ast _ module_info, filename, module, module_len);
1340} 1344}
1341 1345
1342ASAP_FUNC void ASAP_DetectSilence(ASAP_State PTR ast, int seconds) 1346FUNC(void, ASAP_DetectSilence, (P(ASAP_State PTR, ast), P(int, seconds)))
1343{ 1347{
1344 AST silence_cycles = seconds * ASAP_MAIN_CLOCK; 1348 ast _ silence_cycles = seconds * ASAP_MAIN_CLOCK;
1345} 1349}
1346 1350
1347FILE_FUNC void call_6502(ASAP_State PTR ast, int addr, int max_scanlines) 1351PRIVATE FUNC(void, call_6502, (P(ASAP_State PTR, ast), P(int, addr), P(int, max_scanlines)))
1348{ 1352{
1349 AST cpu_pc = addr; 1353 ast _ cpu_pc = addr;
1350 /* put a CIM at 0xd20a and a return address on stack */ 1354 /* put a CIM at 0xd20a and a return address on stack */
1351 dPutByte(0xd20a, 0xd2); 1355 dPutByte(0xd20a, 0xd2);
1352 dPutByte(0x01fe, 0x09); 1356 dPutByte(0x01fe, 0x09);
1353 dPutByte(0x01ff, 0xd2); 1357 dPutByte(0x01ff, 0xd2);
1354 AST cpu_s = 0xfd; 1358 ast _ cpu_s = 0xfd;
1355 Cpu_RunScanlines(ast, max_scanlines); 1359 Cpu_RunScanlines(ast, max_scanlines);
1356} 1360}
1357 1361
1358/* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */ 1362/* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */
1359#define SCANLINES_FOR_INIT (50 * 312) 1363#define SCANLINES_FOR_INIT (50 * 312)
1360 1364
1361FILE_FUNC void call_6502_init(ASAP_State PTR ast, int addr, int a, int x, int y) 1365PRIVATE FUNC(void, call_6502_init, (P(ASAP_State PTR, ast), P(int, addr), P(int, a), P(int, x), P(int, y)))
1362{ 1366{
1363 AST cpu_a = a & 0xff; 1367 ast _ cpu_a = a & 0xff;
1364 AST cpu_x = x & 0xff; 1368 ast _ cpu_x = x & 0xff;
1365 AST cpu_y = y & 0xff; 1369 ast _ cpu_y = y & 0xff;
1366 call_6502(ast, addr, SCANLINES_FOR_INIT); 1370 call_6502(ast, addr, SCANLINES_FOR_INIT);
1367} 1371}
1368 1372
1369ASAP_FUNC void ASAP_PlaySong(ASAP_State PTR ast, int song, int duration) 1373FUNC(void, ASAP_PlaySong, (P(ASAP_State PTR, ast), P(int, song), P(int, duration)))
1370{ 1374{
1371 AST current_song = song; 1375 ast _ current_song = song;
1372 AST current_duration = duration; 1376 ast _ current_duration = duration;
1373 AST blocks_played = 0; 1377 ast _ blocks_played = 0;
1374 AST silence_cycles_counter = AST silence_cycles; 1378 ast _ silence_cycles_counter = ast _ silence_cycles;
1375 AST extra_pokey_mask = AST module_info.channels > 1 ? 0x10 : 0; 1379 ast _ extra_pokey_mask = ast _ module_info.channels > 1 ? 0x10 : 0;
1380 ast _ consol = 8;
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;
1376 PokeySound_Initialize(ast); 1385 PokeySound_Initialize(ast);
1377 AST cycle = 0; 1386 ast _ cycle = 0;
1378 AST cpu_nz = 0; 1387 ast _ cpu_nz = 0;
1379 AST cpu_c = 0; 1388 ast _ cpu_c = 0;
1380 AST cpu_vdi = 0; 1389 ast _ cpu_vdi = 0;
1381 AST scanline_number = 0; 1390 ast _ scanline_number = 0;
1382 AST next_scanline_cycle = 0; 1391 ast _ next_scanline_cycle = 0;
1383 AST timer1_cycle = NEVER; 1392 ast _ timer1_cycle = NEVER;
1384 AST timer2_cycle = NEVER; 1393 ast _ timer2_cycle = NEVER;
1385 AST timer4_cycle = NEVER; 1394 ast _ timer4_cycle = NEVER;
1386 AST irqst = 0xff; 1395 ast _ irqst = 0xff;
1387 switch (AST module_info.type) { 1396 switch (ast _ module_info.type) {
1388 case 'B': 1397 case ASAP_TYPE_SAP_B:
1389 call_6502_init(ast, AST module_info.init, song, 0, 0); 1398 call_6502_init(ast, ast _ module_info.init, song, 0, 0);
1390 break; 1399 break;
1391 case 'C': 1400 case ASAP_TYPE_SAP_C:
1392 case 'c': 1401#ifndef ASAP_ONLY_SAP
1393 case 'z': 1402 case ASAP_TYPE_CMC:
1394 call_6502_init(ast, AST module_info.player + 3, 0x70, AST module_info.music, AST module_info.music >> 8); 1403 case ASAP_TYPE_CM3:
1395 call_6502_init(ast, AST module_info.player + 3, 0x00, song, 0); 1404 case ASAP_TYPE_CMR:
1405 case ASAP_TYPE_CMS:
1406#endif
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);
1409 break;
1410 case ASAP_TYPE_SAP_D:
1411 case ASAP_TYPE_SAP_S:
1412 ast _ cpu_a = song;
1413 ast _ cpu_x = 0x00;
1414 ast _ cpu_y = 0x00;
1415 ast _ cpu_s = 0xff;
1416 ast _ cpu_pc = ast _ module_info.init;
1396 break; 1417 break;
1397 case 'D': 1418#ifndef ASAP_ONLY_SAP
1398 case 'S': 1419 case ASAP_TYPE_DLT:
1399 AST cpu_a = song; 1420 call_6502_init(ast, ast _ module_info.player + 0x100, 0x00, 0x00, ast _ module_info.song_pos[song]);
1400 AST cpu_x = 0x00;
1401 AST cpu_y = 0x00;
1402 AST cpu_s = 0xff;
1403 AST cpu_pc = AST module_info.init;
1404 break; 1421 break;
1405 case 'm': 1422 case ASAP_TYPE_MPT:
1406 call_6502_init(ast, AST module_info.player, 0x00, AST module_info.music >> 8, AST module_info.music); 1423 call_6502_init(ast, ast _ module_info.player, 0x00, ast _ module_info.music >> 8, ast _ module_info.music);
1407 call_6502_init(ast, AST module_info.player, 0x02, AST module_info.song_pos[song], 0); 1424 call_6502_init(ast, ast _ module_info.player, 0x02, ast _ module_info.song_pos[song], 0);
1408 break; 1425 break;
1409 case 'r': 1426 case ASAP_TYPE_RMT:
1410 call_6502_init(ast, AST module_info.player, AST module_info.song_pos[song], AST module_info.music, AST module_info.music >> 8); 1427 call_6502_init(ast, ast _ module_info.player, ast _ module_info.song_pos[song], ast _ module_info.music, ast _ module_info.music >> 8);
1411 break; 1428 break;
1412 case 't': 1429 case ASAP_TYPE_TMC:
1413 case 'T': 1430 case ASAP_TYPE_TM2:
1414 call_6502_init(ast, AST module_info.player, 0x70, AST module_info.music >> 8, AST module_info.music); 1431 call_6502_init(ast, ast _ module_info.player, 0x70, ast _ module_info.music >> 8, ast _ module_info.music);
1415 call_6502_init(ast, AST module_info.player, 0x00, song, 0); 1432 call_6502_init(ast, ast _ module_info.player, 0x00, song, 0);
1416 AST tmc_per_frame_counter = 1; 1433 ast _ tmc_per_frame_counter = 1;
1417 break; 1434 break;
1435#endif
1418 } 1436 }
1419 ASAP_MutePokeyChannels(ast, 0); 1437 ASAP_MutePokeyChannels(ast, 0);
1420} 1438}
1421 1439
1422ASAP_FUNC void ASAP_MutePokeyChannels(ASAP_State PTR ast, int mask) 1440FUNC(void, ASAP_MutePokeyChannels, (P(ASAP_State PTR, ast), P(int, mask)))
1423{ 1441{
1424 PokeySound_Mute(ast, ADDRESSOF AST base_pokey, mask); 1442 PokeySound_Mute(ast, ADDRESSOF ast _ base_pokey, mask);
1425 PokeySound_Mute(ast, ADDRESSOF AST extra_pokey, mask >> 4); 1443 PokeySound_Mute(ast, ADDRESSOF ast _ extra_pokey, mask >> 4);
1426} 1444}
1427 1445
1428ASAP_FUNC abool call_6502_player(ASAP_State PTR ast) 1446FUNC(abool, call_6502_player, (P(ASAP_State PTR, ast)))
1429{ 1447{
1430 int s; 1448 V(int, player) = ast _ module_info.player;
1431 PokeySound_StartFrame(ast); 1449 PokeySound_StartFrame(ast);
1432 switch (AST module_info.type) { 1450 switch (ast _ module_info.type) {
1433 case 'B': 1451 case ASAP_TYPE_SAP_B:
1434 call_6502(ast, AST module_info.player, AST module_info.fastplay); 1452 call_6502(ast, player, ast _ module_info.fastplay);
1435 break; 1453 break;
1436 case 'C': 1454 case ASAP_TYPE_SAP_C:
1437 case 'c': 1455#ifndef ASAP_ONLY_SAP
1438 case 'z': 1456 case ASAP_TYPE_CMC:
1439 call_6502(ast, AST module_info.player + 6, AST module_info.fastplay); 1457 case ASAP_TYPE_CM3:
1458 case ASAP_TYPE_CMR:
1459 case ASAP_TYPE_CMS:
1460#endif
1461 call_6502(ast, player + 6, ast _ module_info.fastplay);
1440 break; 1462 break;
1441 case 'D': 1463 case ASAP_TYPE_SAP_D:
1442 s = AST cpu_s; 1464 if (player >= 0) {
1465 V(int, s)= ast _ cpu_s;
1443#define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff 1466#define PUSH_ON_6502_STACK(x) dPutByte(0x100 + s, x); s = (s - 1) & 0xff
1444#define RETURN_FROM_PLAYER_ADDR 0xd200 1467#define RETURN_FROM_PLAYER_ADDR 0xd200
1445 /* save 6502 state on 6502 stack */ 1468 /* save 6502 state on 6502 stack */
1446 PUSH_ON_6502_STACK(AST cpu_pc >> 8); 1469 PUSH_ON_6502_STACK(ast _ cpu_pc >> 8);
1447 PUSH_ON_6502_STACK(AST cpu_pc & 0xff); 1470 PUSH_ON_6502_STACK(ast _ cpu_pc & 0xff);
1448 PUSH_ON_6502_STACK(((AST cpu_nz | (AST cpu_nz >> 1)) & 0x80) + AST cpu_vdi + \ 1471 PUSH_ON_6502_STACK(((ast _ cpu_nz | (ast _ cpu_nz >> 1)) & 0x80) + ast _ cpu_vdi + \
1449 ((AST cpu_nz & 0xff) == 0 ? Z_FLAG : 0) + AST cpu_c + 0x20); 1472 ((ast _ cpu_nz & 0xff) == 0 ? Z_FLAG : 0) + ast _ cpu_c + 0x20);
1450 PUSH_ON_6502_STACK(AST cpu_a); 1473 PUSH_ON_6502_STACK(ast _ cpu_a);
1451 PUSH_ON_6502_STACK(AST cpu_x); 1474 PUSH_ON_6502_STACK(ast _ cpu_x);
1452 PUSH_ON_6502_STACK(AST cpu_y); 1475 PUSH_ON_6502_STACK(ast _ cpu_y);
1453 /* RTS will jump to 6502 code that restores the state */ 1476 /* RTS will jump to 6502 code that restores the state */
1454 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) >> 8); 1477 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) >> 8);
1455 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) & 0xff); 1478 PUSH_ON_6502_STACK((RETURN_FROM_PLAYER_ADDR - 1) & 0xff);
1456 AST cpu_s = s; 1479 ast _ cpu_s = s;
1457 dPutByte(RETURN_FROM_PLAYER_ADDR, 0x68); /* PLA */ 1480 dPutByte(RETURN_FROM_PLAYER_ADDR, 0x68); /* PLA */
1458 dPutByte(RETURN_FROM_PLAYER_ADDR + 1, 0xa8); /* TAY */ 1481 dPutByte(RETURN_FROM_PLAYER_ADDR + 1, 0xa8); /* TAY */
1459 dPutByte(RETURN_FROM_PLAYER_ADDR + 2, 0x68); /* PLA */ 1482 dPutByte(RETURN_FROM_PLAYER_ADDR + 2, 0x68); /* PLA */
1460 dPutByte(RETURN_FROM_PLAYER_ADDR + 3, 0xaa); /* TAX */ 1483 dPutByte(RETURN_FROM_PLAYER_ADDR + 3, 0xaa); /* TAX */
1461 dPutByte(RETURN_FROM_PLAYER_ADDR + 4, 0x68); /* PLA */ 1484 dPutByte(RETURN_FROM_PLAYER_ADDR + 4, 0x68); /* PLA */
1462 dPutByte(RETURN_FROM_PLAYER_ADDR + 5, 0x40); /* RTI */ 1485 dPutByte(RETURN_FROM_PLAYER_ADDR + 5, 0x40); /* RTI */
1463 AST cpu_pc = AST module_info.player; 1486 ast _ cpu_pc = player;
1464 Cpu_RunScanlines(ast, AST module_info.fastplay); 1487 }
1488 Cpu_RunScanlines(ast, ast _ module_info.fastplay);
1465 break; 1489 break;
1466 case 'S': 1490 case ASAP_TYPE_SAP_S:
1467 Cpu_RunScanlines(ast, AST module_info.fastplay); 1491 Cpu_RunScanlines(ast, ast _ module_info.fastplay);
1468 { 1492 {
1469 int i = dGetByte(0x45) - 1; 1493 V(int, i) = dGetByte(0x45) - 1;
1470 dPutByte(0x45, i); 1494 dPutByte(0x45, i);
1471 if (i == 0) 1495 if (i == 0)
1472 dPutByte(0xb07b, dGetByte(0xb07b) + 1); 1496 dPutByte(0xb07b, dGetByte(0xb07b) + 1);
1473 } 1497 }
1474 break; 1498 break;
1475 case 'm': 1499#ifndef ASAP_ONLY_SAP
1476 case 'r': 1500 case ASAP_TYPE_DLT:
1477 case 'T': 1501 call_6502(ast, player + 0x103, ast _ module_info.fastplay);
1478 call_6502(ast, AST module_info.player + 3, AST module_info.fastplay);
1479 break; 1502 break;
1480 case 't': 1503 case ASAP_TYPE_MPT:
1481 if (--AST tmc_per_frame_counter <= 0) { 1504 case ASAP_TYPE_RMT:
1482 AST tmc_per_frame_counter = AST tmc_per_frame; 1505 case ASAP_TYPE_TM2:
1483 call_6502(ast, AST module_info.player + 3, AST module_info.fastplay); 1506 call_6502(ast, player + 3, ast _ module_info.fastplay);
1507 break;
1508 case ASAP_TYPE_TMC:
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);
1484 } 1512 }
1485 else 1513 else
1486 call_6502(ast, AST module_info.player + 6, AST module_info.fastplay); 1514 call_6502(ast, player + 6, ast _ module_info.fastplay);
1487 break; 1515 break;
1516#endif
1488 } 1517 }
1489 PokeySound_EndFrame(ast, AST module_info.fastplay * 114); 1518 PokeySound_EndFrame(ast, ast _ module_info.fastplay * 114);
1490 if (AST silence_cycles > 0) { 1519 if (ast _ silence_cycles > 0) {
1491 if (PokeySound_IsSilent(ADDRESSOF AST base_pokey) 1520 if (PokeySound_IsSilent(ADDRESSOF ast _ base_pokey)
1492 && PokeySound_IsSilent(ADDRESSOF AST extra_pokey)) { 1521 && PokeySound_IsSilent(ADDRESSOF ast _ extra_pokey)) {
1493 AST silence_cycles_counter -= AST module_info.fastplay * 114; 1522 ast _ silence_cycles_counter -= ast _ module_info.fastplay * 114;
1494 if (AST silence_cycles_counter <= 0) 1523 if (ast _ silence_cycles_counter <= 0)
1495 return FALSE; 1524 return FALSE;
1496 } 1525 }
1497 else 1526 else
1498 AST silence_cycles_counter = AST silence_cycles; 1527 ast _ silence_cycles_counter = ast _ silence_cycles;
1499 } 1528 }
1500 return TRUE; 1529 return TRUE;
1501} 1530}
1502 1531
1503FILE_FUNC int milliseconds_to_blocks(int milliseconds) 1532FUNC(int, ASAP_GetPosition, (P(CONST ASAP_State PTR, ast)))
1533{
1534 return ast _ blocks_played * 10 / (ASAP_SAMPLE_RATE / 100);
1535}
1536
1537FUNC(int, milliseconds_to_blocks, (P(int, milliseconds)))
1504{ 1538{
1505 return milliseconds * (ASAP_SAMPLE_RATE / 100) / 10; 1539 return milliseconds * (ASAP_SAMPLE_RATE / 100) / 10;
1506} 1540}
1507 1541
1508ASAP_FUNC void ASAP_Seek(ASAP_State PTR ast, int position) 1542#ifndef ACTIONSCRIPT
1543
1544FUNC(void, ASAP_Seek, (P(ASAP_State PTR, ast), P(int, position)))
1509{ 1545{
1510 int block = milliseconds_to_blocks(position); 1546 V(int, block) = milliseconds_to_blocks(position);
1511 if (block < AST blocks_played) 1547 if (block < ast _ blocks_played)
1512 ASAP_PlaySong(ast, AST current_song, AST current_duration); 1548 ASAP_PlaySong(ast, ast _ current_song, ast _ current_duration);
1513 while (AST blocks_played + AST samples - AST sample_index < block) { 1549 while (ast _ blocks_played + ast _ samples - ast _ sample_index < block) {
1514 AST blocks_played += AST samples - AST sample_index; 1550 ast _ blocks_played += ast _ samples - ast _ sample_index;
1515 call_6502_player(ast); 1551 call_6502_player(ast);
1516 } 1552 }
1517 AST sample_index += block - AST blocks_played; 1553 ast _ sample_index += block - ast _ blocks_played;
1518 AST blocks_played = block; 1554 ast _ blocks_played = block;
1555}
1556
1557PRIVATE FUNC(void, serialize_int, (P(BYTEARRAY, buffer), P(int, offset), P(int, value)))
1558{
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);
1563}
1564
1565FUNC(void, ASAP_GetWavHeaderForPart, (
1566 P(CONST ASAP_State PTR, ast), P(BYTEARRAY, buffer),
1567 P(ASAP_SampleFormat, format), P(int, blocks)))
1568{
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;
1573 V(int, n_bytes);
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(' ');
1590 buffer[16] = 16;
1591 buffer[17] = 0;
1592 buffer[18] = 0;
1593 buffer[19] = 0;
1594 buffer[20] = 1;
1595 buffer[21] = 0;
1596 buffer[22] = CAST(byte) ast _ module_info.channels;
1597 buffer[23] = 0;
1598 serialize_int(buffer, 24, ASAP_SAMPLE_RATE);
1599 serialize_int(buffer, 28, bytes_per_second);
1600 buffer[32] = CAST(byte) block_size;
1601 buffer[33] = 0;
1602 buffer[34] = CAST(byte) (8 << use_16bit);
1603 buffer[35] = 0;
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);
1609}
1610
1611FUNC(void, ASAP_GetWavHeader, (
1612 P(CONST ASAP_State PTR, ast), P(BYTEARRAY, buffer), P(ASAP_SampleFormat, format)))
1613{
1614 V(int, remaining_blocks) = milliseconds_to_blocks(ast _ current_duration) - ast _ blocks_played;
1615 ASAP_GetWavHeaderForPart(ast, buffer, format, remaining_blocks);
1519} 1616}
1520 1617
1521ASAP_FUNC int ASAP_Generate(ASAP_State PTR ast, VOIDPTR buffer, int buffer_len, 1618#endif /* ACTIONSCRIPT */
1522 ASAP_SampleFormat format) 1619
1620PRIVATE FUNC(int, ASAP_GenerateAt, (P(ASAP_State PTR, ast), P(VOIDPTR, buffer), P(int, buffer_offset), P(int, buffer_len), P(ASAP_SampleFormat, format)))
1523{ 1621{
1524 int block_shift; 1622 V(int, block_shift);
1525 int buffer_blocks; 1623 V(int, buffer_blocks);
1526 int block; 1624 V(int, block);
1527 if (AST silence_cycles > 0 && AST silence_cycles_counter <= 0) 1625 if (ast _ silence_cycles > 0 && ast _ silence_cycles_counter <= 0)
1528 return 0; 1626 return 0;
1529 block_shift = (AST module_info.channels - 1) + (format != ASAP_FORMAT_U8 ? 1 : 0); 1627#ifdef ACTIONSCRIPT
1628 block_shift = 0;
1629#else
1630 block_shift = (ast _ module_info.channels - 1) + (format != ASAP_FORMAT_U8 ? 1 : 0);
1631#endif
1530 buffer_blocks = buffer_len >> block_shift; 1632 buffer_blocks = buffer_len >> block_shift;
1531 if (AST current_duration > 0) { 1633 if (ast _ current_duration > 0) {
1532 int total_blocks = milliseconds_to_blocks(AST current_duration); 1634 V(int, total_blocks) = milliseconds_to_blocks(ast _ current_duration);
1533 if (buffer_blocks > total_blocks - AST blocks_played) 1635 if (buffer_blocks > total_blocks - ast _ blocks_played)
1534 buffer_blocks = total_blocks - AST blocks_played; 1636 buffer_blocks = total_blocks - ast _ blocks_played;
1535 } 1637 }
1536 block = 0; 1638 block = 0;
1537 do { 1639 do {
1538 int blocks = PokeySound_Generate(ast, buffer, block << block_shift, buffer_blocks - block, format); 1640 V(int, blocks) = PokeySound_Generate(ast, CAST(BYTEARRAY) buffer,
1539 AST blocks_played += blocks; 1641 buffer_offset + (block << block_shift), buffer_blocks - block, format);
1642 ast _ blocks_played += blocks;
1540 block += blocks; 1643 block += blocks;
1541 } while (block < buffer_blocks && call_6502_player(ast)); 1644 } while (block < buffer_blocks && call_6502_player(ast));
1542 return block << block_shift; 1645 return block << block_shift;
1543} 1646}
1544 1647
1545#if !defined(JAVA) && !defined(CSHARP) 1648FUNC(int, ASAP_Generate, (P(ASAP_State PTR, ast), P(VOIDPTR, buffer), P(int, buffer_len), P(ASAP_SampleFormat, format)))
1649{
1650 return ASAP_GenerateAt(ast, buffer, 0, buffer_len, format);
1651}
1652
1653#if defined(C) && !defined(ASAP_ONLY_SAP)
1546 1654
1547abool ASAP_ChangeExt(char *filename, const char *ext) 1655abool ASAP_ChangeExt(char *filename, const char *ext)
1548{ 1656{
@@ -1586,7 +1694,6 @@ static byte *put_dec(byte *dest, int value)
1586static byte *put_text_tag(byte *dest, const char *tag, const char *value) 1694static byte *put_text_tag(byte *dest, const char *tag, const char *value)
1587{ 1695{
1588 dest = put_string(dest, tag); 1696 dest = put_string(dest, tag);
1589 *dest++ = ' ';
1590 *dest++ = '"'; 1697 *dest++ = '"';
1591 if (*value == '\0') 1698 if (*value == '\0')
1592 value = "<?>"; 1699 value = "<?>";
@@ -1601,13 +1708,21 @@ static byte *put_text_tag(byte *dest, const char *tag, const char *value)
1601 return dest; 1708 return dest;
1602} 1709}
1603 1710
1711static byte *put_dec_tag(byte *dest, const char *tag, int value)
1712{
1713 dest = put_string(dest, tag);
1714 dest = put_dec(dest, value);
1715 *dest++ = '\r';
1716 *dest++ = '\n';
1717 return dest;
1718}
1719
1604static byte *put_hex_tag(byte *dest, const char *tag, int value) 1720static byte *put_hex_tag(byte *dest, const char *tag, int value)
1605{ 1721{
1606 int i; 1722 int i;
1607 if (value < 0) 1723 if (value < 0)
1608 return dest; 1724 return dest;
1609 dest = put_string(dest, tag); 1725 dest = put_string(dest, tag);
1610 *dest++ = ' ';
1611 for (i = 12; i >= 0; i -= 4) { 1726 for (i = 12; i >= 0; i -= 4) {
1612 int digit = (value >> i) & 0xf; 1727 int digit = (value >> i) & 0xf;
1613 *dest++ = (byte) (digit + (digit < 10 ? '0' : 'A' - 10)); 1728 *dest++ = (byte) (digit + (digit < 10 ? '0' : 'A' - 10));
@@ -1617,38 +1732,54 @@ static byte *put_hex_tag(byte *dest, const char *tag, int value)
1617 return dest; 1732 return dest;
1618} 1733}
1619 1734
1620static byte *put_dec_tag(byte *dest, const char *tag, int value)
1621{
1622 dest = put_string(dest, tag);
1623 *dest++ = ' ';
1624 dest = put_dec(dest, value);
1625 *dest++ = '\r';
1626 *dest++ = '\n';
1627 return dest;
1628}
1629
1630static byte *start_sap_header(byte *dest, const ASAP_ModuleInfo *module_info) 1735static byte *start_sap_header(byte *dest, const ASAP_ModuleInfo *module_info)
1631{ 1736{
1632 dest = put_string(dest, "SAP\r\n"); 1737 dest = put_string(dest, "SAP\r\n");
1633 dest = put_text_tag(dest, "AUTHOR", module_info->author); 1738 dest = put_text_tag(dest, "AUTHOR ", module_info->author);
1634 if (dest == NULL) 1739 if (dest == NULL)
1635 return NULL; 1740 return NULL;
1636 dest = put_text_tag(dest, "NAME", module_info->name); 1741 dest = put_text_tag(dest, "NAME ", module_info->name);
1637 if (dest == NULL) 1742 if (dest == NULL)
1638 return NULL; 1743 return NULL;
1639 dest = put_text_tag(dest, "DATE", module_info->date); 1744 dest = put_text_tag(dest, "DATE ", module_info->date);
1640 if (dest == NULL) 1745 if (dest == NULL)
1641 return NULL; 1746 return NULL;
1642 if (module_info->songs > 1) { 1747 if (module_info->songs > 1) {
1643 dest = put_dec_tag(dest, "SONGS", module_info->songs); 1748 dest = put_dec_tag(dest, "SONGS ", module_info->songs);
1644 if (module_info->default_song > 0) 1749 if (module_info->default_song > 0)
1645 dest = put_dec_tag(dest, "DEFSONG", module_info->default_song); 1750 dest = put_dec_tag(dest, "DEFSONG ", module_info->default_song);
1646 } 1751 }
1647 if (module_info->channels > 1) 1752 if (module_info->channels > 1)
1648 dest = put_string(dest, "STEREO\r\n"); 1753 dest = put_string(dest, "STEREO\r\n");
1649 return dest; 1754 return dest;
1650} 1755}
1651 1756
1757static char *two_digits(char *s, int x)
1758{
1759 s[0] = '0' + x / 10;
1760 s[1] = '0' + x % 10;
1761 return s + 2;
1762}
1763
1764void ASAP_DurationToString(char *s, int duration)
1765{
1766 if (duration >= 0 && duration < 100 * 60 * 1000) {
1767 int seconds = duration / 1000;
1768 s = two_digits(s, seconds / 60);
1769 *s++ = ':';
1770 s = two_digits(s, seconds % 60);
1771 duration %= 1000;
1772 if (duration != 0) {
1773 *s++ = '.';
1774 s = two_digits(s, duration / 10);
1775 duration %= 10;
1776 if (duration != 0)
1777 *s++ = '0' + duration;
1778 }
1779 }
1780 *s = '\0';
1781}
1782
1652static byte *put_durations(byte *dest, const ASAP_ModuleInfo *module_info) 1783static byte *put_durations(byte *dest, const ASAP_ModuleInfo *module_info)
1653{ 1784{
1654 int song; 1785 int song;
@@ -1677,16 +1808,15 @@ static byte *put_sap_header(byte *dest, const ASAP_ModuleInfo *module_info, char
1677 *dest++ = '\r'; 1808 *dest++ = '\r';
1678 *dest++ = '\n'; 1809 *dest++ = '\n';
1679 if (module_info->fastplay != 312) 1810 if (module_info->fastplay != 312)
1680 dest = put_dec_tag(dest, "FASTPLAY", module_info->fastplay); 1811 dest = put_dec_tag(dest, "FASTPLAY ", module_info->fastplay);
1681 dest = put_hex_tag(dest, "MUSIC", music); 1812 dest = put_hex_tag(dest, "MUSIC ", music);
1682 dest = put_hex_tag(dest, "INIT", init); 1813 dest = put_hex_tag(dest, "INIT ", init);
1683 dest = put_hex_tag(dest, "PLAYER", player); 1814 dest = put_hex_tag(dest, "PLAYER ", player);
1684 dest = put_durations(dest, module_info); 1815 dest = put_durations(dest, module_info);
1685 return dest; 1816 return dest;
1686} 1817}
1687 1818
1688int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte ARRAY module, 1819int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const BYTEARRAY module, int module_len, BYTEARRAY out_module)
1689 int module_len, byte ARRAY out_module)
1690{ 1820{
1691 byte *dest; 1821 byte *dest;
1692 int i; 1822 int i;
@@ -1702,7 +1832,7 @@ int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte ARRAY modu
1702 || memcmp(module + i, "DATE ", 5) == 0 1832 || memcmp(module + i, "DATE ", 5) == 0
1703 || memcmp(module + i, "SONGS ", 6) == 0 1833 || memcmp(module + i, "SONGS ", 6) == 0
1704 || memcmp(module + i, "DEFSONG ", 8) == 0 1834 || memcmp(module + i, "DEFSONG ", 8) == 0
1705 || memcmp(module + i, "STEREO", 6) == 0 1835 || memcmp(module + i, "STEREO\r", 7) == 0
1706 || memcmp(module + i, "TIME ", 5) == 0) { 1836 || memcmp(module + i, "TIME ", 5) == 0) {
1707 while (i < module_len && module[i++] != 0x0a); 1837 while (i < module_len && module[i++] != 0x0a);
1708 } 1838 }
@@ -1724,12 +1854,15 @@ int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte ARRAY modu
1724#define RMT_INIT 0x0c80 1854#define RMT_INIT 0x0c80
1725#define TM2_INIT 0x1080 1855#define TM2_INIT 0x1080
1726 1856
1727const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_info, 1857const char *ASAP_CanConvert(
1728 const byte ARRAY module, int module_len) 1858 const char *filename, const ASAP_ModuleInfo *module_info,
1859 const BYTEARRAY module, int module_len)
1729{ 1860{
1730 (void)filename; 1861 (void) filename;
1731 switch (module_info->type) { 1862 switch (module_info->type) {
1732 case 'B': 1863 case ASAP_TYPE_SAP_B:
1864 if ((module_info->init == 0x3fb || module_info->init == 0x3f9) && module_info->player == 0x503)
1865 return "dlt";
1733 if (module_info->init == 0x4f3 || module_info->init == 0xf4f3 || module_info->init == 0x4ef) 1866 if (module_info->init == 0x4f3 || module_info->init == 0xf4f3 || module_info->init == 0x4ef)
1734 return module_info->fastplay == 156 ? "mpd" : "mpt"; 1867 return module_info->fastplay == 156 ? "mpd" : "mpt";
1735 if (module_info->init == RMT_INIT) 1868 if (module_info->init == RMT_INIT)
@@ -1741,19 +1874,28 @@ const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_
1741 if (module_info->init == TM2_INIT) 1874 if (module_info->init == TM2_INIT)
1742 return "tm2"; 1875 return "tm2";
1743 break; 1876 break;
1744 case 'C': 1877 case ASAP_TYPE_SAP_C:
1745 if (module_info->player == 0x500 || module_info->player == 0xf500) { 1878 if (module_info->player == 0x500 || module_info->player == 0xf500) {
1746 if (module_info->fastplay == 156) 1879 if (module_info->fastplay == 156)
1747 return "dmc"; 1880 return "dmc";
1748 return module[module_len - 170] == 0x1e ? "cmr" : "cmc"; 1881 if (module_info->channels > 1)
1882 return "cms";
1883 if (module[module_len - 170] == 0x1e)
1884 return "cmr";
1885 if (module[module_len - 909] == 0x30)
1886 return "cm3";
1887 return "cmc";
1749 } 1888 }
1750 break; 1889 break;
1751 case 'c': 1890 case ASAP_TYPE_CMC:
1752 case 'z': 1891 case ASAP_TYPE_CM3:
1753 case 'm': 1892 case ASAP_TYPE_CMR:
1754 case 'r': 1893 case ASAP_TYPE_CMS:
1755 case 't': 1894 case ASAP_TYPE_DLT:
1756 case 'T': 1895 case ASAP_TYPE_MPT:
1896 case ASAP_TYPE_RMT:
1897 case ASAP_TYPE_TMC:
1898 case ASAP_TYPE_TM2:
1757 return "sap"; 1899 return "sap";
1758 default: 1900 default:
1759 break; 1901 break;
@@ -1761,8 +1903,9 @@ const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_
1761 return NULL; 1903 return NULL;
1762} 1904}
1763 1905
1764int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info, 1906int ASAP_Convert(
1765 const byte ARRAY module, int module_len, byte ARRAY out_module) 1907 const char *filename, const ASAP_ModuleInfo *module_info,
1908 const BYTEARRAY module, int module_len, BYTEARRAY out_module)
1766{ 1909{
1767 (void) filename; 1910 (void) filename;
1768 int out_len; 1911 int out_len;
@@ -1772,27 +1915,80 @@ int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
1772 static const int tmc_player[4] = { 3, -9, -10, -10 }; 1915 static const int tmc_player[4] = { 3, -9, -10, -10 };
1773 static const int tmc_init[4] = { -14, -16, -17, -17 }; 1916 static const int tmc_init[4] = { -14, -16, -17, -17 };
1774 switch (module_info->type) { 1917 switch (module_info->type) {
1775 case 'B': 1918 case ASAP_TYPE_SAP_B:
1776 case 'C': 1919 case ASAP_TYPE_SAP_C:
1777 out_len = module[module_info->header_len + 4] + (module[module_info->header_len + 5] << 8) 1920 out_len = UWORD(module, module_info->header_len + 4) - UWORD(module, module_info->header_len + 2) + 7;
1778 - module[module_info->header_len + 2] - (module[module_info->header_len + 3] << 8) + 7;
1779 if (out_len < 7 || module_info->header_len + out_len >= module_len) 1921 if (out_len < 7 || module_info->header_len + out_len >= module_len)
1780 return -1; 1922 return -1;
1781 memcpy(out_module, module + module_info->header_len, out_len); 1923 memcpy(out_module, module + module_info->header_len, out_len);
1782 return out_len; 1924 return out_len;
1783 case 'c': 1925 case ASAP_TYPE_CMC:
1784 case 'z': 1926 case ASAP_TYPE_CM3:
1927 case ASAP_TYPE_CMR:
1928 case ASAP_TYPE_CMS:
1785 dest = put_sap_header(out_module, module_info, 'C', module_info->music, -1, module_info->player); 1929 dest = put_sap_header(out_module, module_info, 'C', module_info->music, -1, module_info->player);
1786 if (dest == NULL) 1930 if (dest == NULL)
1787 return -1; 1931 return -1;
1788 memcpy(dest, module, module_len); 1932 memcpy(dest, module, module_len);
1933 dest[0] = 0xff; /* some modules start with zeros */
1934 dest[1] = 0xff;
1789 dest += module_len; 1935 dest += module_len;
1790 memcpy(dest, cmc_obx + 2, sizeof(cmc_obx) - 2); 1936 if (module_info->type == ASAP_TYPE_CM3) {
1791 if (module_info->type == 'z') 1937 memcpy(dest, cm3_obx + 2, sizeof(cm3_obx) - 2);
1792 memcpy(dest + 4 + CMR_BASS_TABLE_OFFSET, cmr_bass_table, sizeof(cmr_bass_table)); 1938 dest += sizeof(cm3_obx) - 2;
1793 dest += sizeof(cmc_obx) - 2; 1939 }
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;
1943 }
1944 else {
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;
1949 }
1950 return dest - out_module;
1951 case ASAP_TYPE_DLT:
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);
1955 }
1956 else {
1957 addr = module_info->player - 5;
1958 dest = put_sap_header(out_module, module_info, 'B', -1, addr, module_info->player + 0x103);
1959 }
1960 if (dest == NULL)
1961 return -1;
1962 memcpy(dest, module, module_len);
1963 if (module_len == 0x2c06) {
1964 dest[4] = 0;
1965 dest[5] = 0x4c;
1966 dest[0x2c06] = 0;
1967 }
1968 dest += 0x2c07;
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);
1980 }
1981 else {
1982 *dest++ = 0xa0; /* ldy #0 */
1983 *dest++ = 0;
1984 }
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;
1794 return dest - out_module; 1990 return dest - out_module;
1795 case 'm': 1991 case ASAP_TYPE_MPT:
1796 if (module_info->songs != 1) { 1992 if (module_info->songs != 1) {
1797 addr = module_info->player - 17 - module_info->songs; 1993 addr = module_info->player - 17 - module_info->songs;
1798 dest = put_sap_header(out_module, module_info, 'B', -1, module_info->player - 17, module_info->player + 3); 1994 dest = put_sap_header(out_module, module_info, 'B', -1, module_info->player - 17, module_info->player + 3);
@@ -1839,7 +2035,7 @@ int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
1839 memcpy(dest, mpt_obx + 6, sizeof(mpt_obx) - 6); 2035 memcpy(dest, mpt_obx + 6, sizeof(mpt_obx) - 6);
1840 dest += sizeof(mpt_obx) - 6; 2036 dest += sizeof(mpt_obx) - 6;
1841 return dest - out_module; 2037 return dest - out_module;
1842 case 'r': 2038 case ASAP_TYPE_RMT:
1843 dest = put_sap_header(out_module, module_info, 'B', -1, RMT_INIT, module_info->player + 3); 2039 dest = put_sap_header(out_module, module_info, 'B', -1, RMT_INIT, module_info->player + 3);
1844 if (dest == NULL) 2040 if (dest == NULL)
1845 return -1; 2041 return -1;
@@ -1882,7 +2078,7 @@ int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
1882 dest += sizeof(rmt8_obx) - 2; 2078 dest += sizeof(rmt8_obx) - 2;
1883 } 2079 }
1884 return dest - out_module; 2080 return dest - out_module;
1885 case 't': 2081 case ASAP_TYPE_TMC:
1886 player = module_info->player + tmc_player[module[0x25] - 1]; 2082 player = module_info->player + tmc_player[module[0x25] - 1];
1887 addr = player + tmc_init[module[0x25] - 1]; 2083 addr = player + tmc_init[module[0x25] - 1];
1888 if (module_info->songs != 1) 2084 if (module_info->songs != 1)
@@ -1959,7 +2155,7 @@ int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
1959 memcpy(dest, tmc_obx + 6, sizeof(tmc_obx) - 6); 2155 memcpy(dest, tmc_obx + 6, sizeof(tmc_obx) - 6);
1960 dest += sizeof(tmc_obx) - 6; 2156 dest += sizeof(tmc_obx) - 6;
1961 return dest - out_module; 2157 return dest - out_module;
1962 case 'T': 2158 case ASAP_TYPE_TM2:
1963 dest = put_sap_header(out_module, module_info, 'B', -1, TM2_INIT, module_info->player + 3); 2159 dest = put_sap_header(out_module, module_info, 'B', -1, TM2_INIT, module_info->player + 3);
1964 if (dest == NULL) 2160 if (dest == NULL)
1965 return -1; 2161 return -1;
@@ -2007,4 +2203,4 @@ int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
2007 } 2203 }
2008} 2204}
2009 2205
2010#endif /* !defined(JAVA) && !defined(CSHARP) */ 2206#endif /* defined(C) && !defined(ASAP_ONLY_SAP) */