diff options
Diffstat (limited to 'apps/codecs/libasap/asap.c')
-rw-r--r-- | apps/codecs/libasap/asap.c | 1796 |
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 | |||
43 | CONST_LOOKUP(byte, cmr_bass_table) = { | ||
44 | 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E, | ||
45 | 0x38, 0x35, (byte) 0x88, 0x7F, 0x79, 0x73, 0x6C, 0x67, | ||
46 | 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F, | ||
47 | 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28, | ||
48 | 0x25, 0x24, 0x21, 0x1F, 0x1E | ||
49 | }; | ||
50 | 25 | ||
51 | ASAP_FUNC int ASAP_GetByte(ASAP_State PTR ast, int addr) | 26 | FUNC(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 | ||
69 | ASAP_FUNC void ASAP_PutByte(ASAP_State PTR ast, int addr, int data) | 47 | FUNC(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 | ||
106 | CONST_LOOKUP(int, perframe2fastplay) = { 312, 312 / 2, 312 / 3, 312 / 4 }; | 104 | #ifndef ASAP_ONLY_SAP |
107 | 105 | ||
108 | FILE_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) | 112 | CONST_ARRAY(byte, cmr_bass_table) |
113 | 0x5C, 0x56, 0x50, 0x4D, 0x47, 0x44, 0x41, 0x3E, | ||
114 | 0x38, 0x35, CAST(byte) (0x88), 0x7F, 0x79, 0x73, 0x6C, 0x67, | ||
115 | 0x60, 0x5A, 0x55, 0x51, 0x4C, 0x48, 0x43, 0x3F, | ||
116 | 0x3D, 0x39, 0x34, 0x33, 0x30, 0x2D, 0x2A, 0x28, | ||
117 | 0x25, 0x24, 0x21, 0x1F, 0x1E | ||
118 | END_CONST_ARRAY; | ||
119 | |||
120 | CONST_ARRAY(int, perframe2fastplay) | ||
121 | 312, 312 / 2, 312 / 3, 312 / 4 | ||
122 | END_CONST_ARRAY; | ||
123 | |||
124 | /* Loads native module (anything except SAP) and 6502 player routine. */ | ||
125 | PRIVATE FUNC(abool, load_native, ( | ||
126 | P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), | ||
127 | P(CONST BYTEARRAY, module), P(int, module_len), P(RESOURCE, player))) | ||
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 | ||
202 | FILE_FUNC void set_song_duration(ASAP_ModuleInfo PTR module_info, int player_calls) | 164 | PRIVATE 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 | ||
212 | FILE_FUNC void parse_cmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) | 174 | PRIVATE 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 | ||
286 | FILE_FUNC abool parse_cmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 248 | PRIVATE 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 | ||
314 | FILE_FUNC void parse_mpt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, | 282 | PRIVATE 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 | |||
290 | PRIVATE 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 | |||
304 | PRIVATE FUNC(void, parse_dlt_song, ( | ||
305 | P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), | ||
306 | P(BOOLARRAY, seen), P(int, pos))) | ||
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 | |||
341 | PRIVATE FUNC(abool, parse_dlt, ( | ||
342 | P(ASAP_State PTR, ast), P(ASAP_ModuleInfo PTR, module_info), | ||
343 | P(CONST BYTEARRAY, module), P(int, module_len))) | ||
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 | |||
367 | PRIVATE FUNC(void, parse_mpt_song, ( | ||
368 | P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), | ||
369 | P(BOOLARRAY, global_seen), P(int, song_len), P(int, pos))) | ||
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 | ||
389 | FILE_FUNC abool parse_mpt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 443 | PRIVATE 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 | ||
422 | CONST_LOOKUP(byte, rmt_volume_silent) = { 16, 8, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }; | 477 | CONST_ARRAY(byte, rmt_volume_silent) |
478 | 16, 8, 4, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 | ||
479 | END_CONST_ARRAY; | ||
423 | 480 | ||
424 | FILE_FUNC int rmt_instrument_frames(const byte ARRAY module, int instrument, int volume, int volume_frame, abool extra_pokey) | 481 | PRIVATE FUNC(int, rmt_instrument_frames, ( |
482 | P(CONST BYTEARRAY, module), P(int, instrument), | ||
483 | P(int, volume), P(int, volume_frame), P(abool, extra_pokey))) | ||
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 | ||
495 | FILE_FUNC void parse_rmt_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, | 552 | PRIVATE 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 | ||
606 | FILE_FUNC abool parse_rmt(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 664 | PRIVATE 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 | ||
658 | FILE_FUNC void parse_tmc_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) | 715 | PRIVATE 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 | ||
717 | FILE_FUNC abool parse_tmc(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 775 | PRIVATE 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 | ||
759 | FILE_FUNC void parse_tm2_song(ASAP_ModuleInfo PTR module_info, const byte ARRAY module, int pos) | 818 | PRIVATE 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 | ||
832 | FILE_FUNC abool parse_tm2(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 892 | PRIVATE 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 | |||
883 | static 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 | ||
904 | static abool parse_dec(int *retval, const char *p, int minval, int maxval) | 944 | PRIVATE 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 | ||
922 | static abool parse_text(char *retval, const char *p) | 954 | PRIVATE 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 | ||
942 | int ASAP_ParseDuration(const char *s) | 972 | PRIVATE 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 | ||
975 | static char *two_digits(char *s, int x) | 990 | PRIVATE 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 | ||
982 | void ASAP_DurationToString(char *s, int duration) | 1014 | FUNC(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) */ | 1059 | PRIVATE FUNC(abool, parse_sap_header, ( |
1003 | 1060 | P(ASAP_ModuleInfo PTR, module_info), P(CONST BYTEARRAY, module), P(int, module_len))) | |
1004 | FILE_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 | ||
1138 | FILE_FUNC abool parse_sap(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 1180 | PRIVATE 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 | ||
1167 | FILE_FUNC int get_packed_ext(STRING filename) | 1210 | PRIVATE 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 | ||
1202 | FILE_FUNC abool is_our_ext(int ext) | 1225 | PRIVATE 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 | ||
1221 | ASAP_FUNC abool ASAP_IsOurFile(STRING filename) | 1249 | FUNC(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 | ||
1227 | ASAP_FUNC abool ASAP_IsOurExt(STRING ext) | 1255 | FUNC(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 | ||
1238 | FILE_FUNC abool parse_file(ASAP_State PTR ast, ASAP_ModuleInfo PTR module_info, | 1261 | PRIVATE 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 | ||
1329 | ASAP_FUNC abool ASAP_GetModuleInfo(ASAP_ModuleInfo PTR module_info, STRING filename, | 1331 | FUNC(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 | ||
1335 | ASAP_FUNC abool ASAP_Load(ASAP_State PTR ast, STRING filename, | 1338 | FUNC(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 | ||
1342 | ASAP_FUNC void ASAP_DetectSilence(ASAP_State PTR ast, int seconds) | 1346 | FUNC(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 | ||
1347 | FILE_FUNC void call_6502(ASAP_State PTR ast, int addr, int max_scanlines) | 1351 | PRIVATE 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 | ||
1361 | FILE_FUNC void call_6502_init(ASAP_State PTR ast, int addr, int a, int x, int y) | 1365 | PRIVATE 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 | ||
1369 | ASAP_FUNC void ASAP_PlaySong(ASAP_State PTR ast, int song, int duration) | 1373 | FUNC(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 | ||
1422 | ASAP_FUNC void ASAP_MutePokeyChannels(ASAP_State PTR ast, int mask) | 1440 | FUNC(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 | ||
1428 | ASAP_FUNC abool call_6502_player(ASAP_State PTR ast) | 1446 | FUNC(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 | ||
1503 | FILE_FUNC int milliseconds_to_blocks(int milliseconds) | 1532 | FUNC(int, ASAP_GetPosition, (P(CONST ASAP_State PTR, ast))) |
1533 | { | ||
1534 | return ast _ blocks_played * 10 / (ASAP_SAMPLE_RATE / 100); | ||
1535 | } | ||
1536 | |||
1537 | FUNC(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 | ||
1508 | ASAP_FUNC void ASAP_Seek(ASAP_State PTR ast, int position) | 1542 | #ifndef ACTIONSCRIPT |
1543 | |||
1544 | FUNC(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 | |||
1557 | PRIVATE 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 | |||
1565 | FUNC(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 | |||
1611 | FUNC(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 | ||
1521 | ASAP_FUNC int ASAP_Generate(ASAP_State PTR ast, VOIDPTR buffer, int buffer_len, | 1618 | #endif /* ACTIONSCRIPT */ |
1522 | ASAP_SampleFormat format) | 1619 | |
1620 | PRIVATE FUNC(int, ASAP_GenerateAt, (P(ASAP_State PTR, ast), P(VOIDPTR, buffer), P(int, buffer_offset), P(int, buffer_len), P(ASAP_SampleFormat, format))) | ||
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) | 1648 | FUNC(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 | ||
1547 | abool ASAP_ChangeExt(char *filename, const char *ext) | 1655 | abool ASAP_ChangeExt(char *filename, const char *ext) |
1548 | { | 1656 | { |
@@ -1586,7 +1694,6 @@ static byte *put_dec(byte *dest, int value) | |||
1586 | static byte *put_text_tag(byte *dest, const char *tag, const char *value) | 1694 | static 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 | ||
1711 | static 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 | |||
1604 | static byte *put_hex_tag(byte *dest, const char *tag, int value) | 1720 | static 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 | ||
1620 | static 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 | |||
1630 | static byte *start_sap_header(byte *dest, const ASAP_ModuleInfo *module_info) | 1735 | static 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 | ||
1757 | static 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 | |||
1764 | void 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 | |||
1652 | static byte *put_durations(byte *dest, const ASAP_ModuleInfo *module_info) | 1783 | static 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 | ||
1688 | int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte ARRAY module, | 1819 | int 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 | ||
1727 | const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_info, | 1857 | const 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 | ||
1764 | int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info, | 1906 | int 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) */ |