Mercurial > audlegacy-plugins
comparison src/psf2/eng_psf.c @ 2737:62cc6d667119
Import a bunch of stuff for new psf2 plugin.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 30 Jun 2008 20:20:53 -0500 |
parents | |
children | f0547285577e |
comparison
equal
deleted
inserted
replaced
2731:324f950774cb | 2737:62cc6d667119 |
---|---|
1 /* | |
2 Audio Overload SDK - PSF file format engine | |
3 | |
4 Copyright (c) 2007 R. Belmont and Richard Bannister. | |
5 | |
6 All rights reserved. | |
7 | |
8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |
9 | |
10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |
11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
12 * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | |
13 | |
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
15 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
16 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
17 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
18 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
19 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
20 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
21 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
22 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
23 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 */ | |
26 | |
27 #include <stdio.h> | |
28 #include <string.h> | |
29 #include <stdlib.h> | |
30 | |
31 #include "ao.h" | |
32 #include "eng_protos.h" | |
33 #include "cpuintrf.h" | |
34 #include "psx.h" | |
35 | |
36 #include "peops/stdafx.h" | |
37 #include "peops/externals.h" | |
38 #include "peops/regs.h" | |
39 #include "peops/registers.h" | |
40 #include "peops/spu.h" | |
41 | |
42 | |
43 #include "corlett.h" | |
44 | |
45 #define DEBUG_LOADER (0) | |
46 | |
47 static corlett_t *c = NULL; | |
48 static char psfby[256]; | |
49 char *spu_pOutput; | |
50 int psf_refresh = -1; | |
51 | |
52 | |
53 // main RAM | |
54 extern uint32 psx_ram[((2*1024*1024)/4)+4]; | |
55 extern uint32 psx_scratch[0x400]; | |
56 extern uint32 initial_ram[((2*1024*1024)/4)+4]; | |
57 extern uint32 initial_scratch[0x400]; | |
58 static uint32 initialPC, initialGP, initialSP; | |
59 | |
60 extern void mips_init( void ); | |
61 extern void mips_reset( void *param ); | |
62 extern int mips_execute( int cycles ); | |
63 extern void mips_set_info(UINT32 state, union cpuinfo *info); | |
64 extern void psx_hw_init(void); | |
65 extern void psx_hw_slice(void); | |
66 extern void psx_hw_frame(void); | |
67 extern void setlength(int32 stop, int32 fade); | |
68 | |
69 int32 psf_start(uint8 *buffer, uint32 length) | |
70 { | |
71 uint8 *file, *lib_decoded, *lib_raw_file, *alib_decoded; | |
72 uint32 offset, plength, PC, SP, GP, lengthMS, fadeMS; | |
73 uint64 file_len, lib_len, lib_raw_length, alib_len; | |
74 corlett_t *lib; | |
75 int i; | |
76 union cpuinfo mipsinfo; | |
77 | |
78 // clear PSX work RAM before we start scribbling in it | |
79 memset(psx_ram, 0, 2*1024*1024); | |
80 | |
81 // printf("Length = %d\n", length); | |
82 | |
83 // Decode the current GSF | |
84 if (corlett_decode(buffer, length, &file, &file_len, &c) != AO_SUCCESS) | |
85 { | |
86 return AO_FAIL; | |
87 } | |
88 | |
89 // printf("file_len %d reserve %d\n", file_len, c->res_size); | |
90 | |
91 // check for PSX EXE signature | |
92 if (strncmp((char *)file, "PS-X EXE", 8)) | |
93 { | |
94 return AO_FAIL; | |
95 } | |
96 | |
97 #if DEBUG_LOADER | |
98 offset = file[0x18] | file[0x19]<<8 | file[0x1a]<<16 | file[0x1b]<<24; | |
99 printf("Text section start: %x\n", offset); | |
100 offset = file[0x1c] | file[0x1d]<<8 | file[0x1e]<<16 | file[0x1f]<<24; | |
101 printf("Text section size: %x\n", offset); | |
102 printf("Region: [%s]\n", &file[0x4c]); | |
103 printf("refresh: [%s]\n", c->inf_refresh); | |
104 #endif | |
105 | |
106 if (c->inf_refresh[0] == '5') | |
107 { | |
108 psf_refresh = 50; | |
109 } | |
110 if (c->inf_refresh[0] == '6') | |
111 { | |
112 psf_refresh = 60; | |
113 } | |
114 | |
115 PC = file[0x10] | file[0x11]<<8 | file[0x12]<<16 | file[0x13]<<24; | |
116 GP = file[0x14] | file[0x15]<<8 | file[0x16]<<16 | file[0x17]<<24; | |
117 SP = file[0x30] | file[0x31]<<8 | file[0x32]<<16 | file[0x33]<<24; | |
118 | |
119 #if DEBUG_LOADER | |
120 printf("Top level: PC %x GP %x SP %x\n", PC, GP, SP); | |
121 #endif | |
122 | |
123 // Get the library file, if any | |
124 if (c->lib[0] != 0) | |
125 { | |
126 uint64 tmp_length; | |
127 | |
128 #if DEBUG_LOADER | |
129 printf("Loading library: %s\n", c->lib); | |
130 #endif | |
131 if (ao_get_lib(c->lib, &lib_raw_file, &tmp_length) != AO_SUCCESS) | |
132 { | |
133 return AO_FAIL; | |
134 } | |
135 lib_raw_length = tmp_length; | |
136 | |
137 if (corlett_decode(lib_raw_file, lib_raw_length, &lib_decoded, &lib_len, &lib) != AO_SUCCESS) | |
138 { | |
139 free(lib_raw_file); | |
140 return AO_FAIL; | |
141 } | |
142 | |
143 // Free up raw file | |
144 free(lib_raw_file); | |
145 | |
146 if (strncmp((char *)lib_decoded, "PS-X EXE", 8)) | |
147 { | |
148 printf("Major error! PSF was OK, but referenced library is not!\n"); | |
149 free(lib); | |
150 return AO_FAIL; | |
151 } | |
152 | |
153 #if DEBUG_LOADER | |
154 offset = lib_decoded[0x18] | lib_decoded[0x19]<<8 | lib_decoded[0x1a]<<16 | lib_decoded[0x1b]<<24; | |
155 printf("Text section start: %x\n", offset); | |
156 offset = lib_decoded[0x1c] | lib_decoded[0x1d]<<8 | lib_decoded[0x1e]<<16 | lib_decoded[0x1f]<<24; | |
157 printf("Text section size: %x\n", offset); | |
158 printf("Region: [%s]\n", &lib_decoded[0x4c]); | |
159 printf("refresh: [%s]\n", lib->inf_refresh); | |
160 #endif | |
161 | |
162 // if the original file had no refresh tag, give the lib a shot | |
163 if (psf_refresh == -1) | |
164 { | |
165 if (lib->inf_refresh[0] == '5') | |
166 { | |
167 psf_refresh = 50; | |
168 } | |
169 if (lib->inf_refresh[0] == '6') | |
170 { | |
171 psf_refresh = 60; | |
172 } | |
173 } | |
174 | |
175 PC = lib_decoded[0x10] | lib_decoded[0x11]<<8 | lib_decoded[0x12]<<16 | lib_decoded[0x13]<<24; | |
176 GP = lib_decoded[0x14] | lib_decoded[0x15]<<8 | lib_decoded[0x16]<<16 | lib_decoded[0x17]<<24; | |
177 SP = lib_decoded[0x30] | lib_decoded[0x31]<<8 | lib_decoded[0x32]<<16 | lib_decoded[0x33]<<24; | |
178 | |
179 #if DEBUG_LOADER | |
180 printf("Library: PC %x GP %x SP %x\n", PC, GP, SP); | |
181 #endif | |
182 | |
183 // now patch the file into RAM | |
184 offset = lib_decoded[0x18] | lib_decoded[0x19]<<8 | lib_decoded[0x1a]<<16 | lib_decoded[0x1b]<<24; | |
185 offset &= 0x3fffffff; // kill any MIPS cache segment indicators | |
186 plength = lib_decoded[0x1c] | lib_decoded[0x1d]<<8 | lib_decoded[0x1e]<<16 | lib_decoded[0x1f]<<24; | |
187 #if DEBUG_LOADER | |
188 printf("library offset: %x plength: %d\n", offset, plength); | |
189 #endif | |
190 memcpy(&psx_ram[offset/4], lib_decoded+2048, plength); | |
191 | |
192 // Dispose the corlett structure for the lib - we don't use it | |
193 free(lib); | |
194 } | |
195 | |
196 // now patch the main file into RAM OVER the libraries (but not the aux lib) | |
197 offset = file[0x18] | file[0x19]<<8 | file[0x1a]<<16 | file[0x1b]<<24; | |
198 offset &= 0x3fffffff; // kill any MIPS cache segment indicators | |
199 plength = file[0x1c] | file[0x1d]<<8 | file[0x1e]<<16 | file[0x1f]<<24; | |
200 | |
201 // Philosoma has an illegal "plength". *sigh* | |
202 if (plength > (file_len-2048)) | |
203 { | |
204 plength = file_len-2048; | |
205 } | |
206 memcpy(&psx_ram[offset/4], file+2048, plength); | |
207 | |
208 // load any auxiliary libraries now | |
209 for (i = 0; i < 8; i++) | |
210 { | |
211 if (c->libaux[i][0] != 0) | |
212 { | |
213 uint64 tmp_length; | |
214 | |
215 #if DEBUG_LOADER | |
216 printf("Loading aux library: %s\n", c->libaux[i]); | |
217 #endif | |
218 | |
219 if (ao_get_lib(c->libaux[i], &lib_raw_file, &tmp_length) != AO_SUCCESS) | |
220 { | |
221 return AO_FAIL; | |
222 } | |
223 lib_raw_length = tmp_length; | |
224 | |
225 if (corlett_decode(lib_raw_file, lib_raw_length, &alib_decoded, &alib_len, &lib) != AO_SUCCESS) | |
226 { | |
227 free(lib_raw_file); | |
228 return AO_FAIL; | |
229 } | |
230 | |
231 // Free up raw file | |
232 free(lib_raw_file); | |
233 | |
234 if (strncmp((char *)alib_decoded, "PS-X EXE", 8)) | |
235 { | |
236 printf("Major error! PSF was OK, but referenced library is not!\n"); | |
237 free(lib); | |
238 return AO_FAIL; | |
239 } | |
240 | |
241 #if DEBUG_LOADER | |
242 offset = alib_decoded[0x18] | alib_decoded[0x19]<<8 | alib_decoded[0x1a]<<16 | alib_decoded[0x1b]<<24; | |
243 printf("Text section start: %x\n", offset); | |
244 offset = alib_decoded[0x1c] | alib_decoded[0x1d]<<8 | alib_decoded[0x1e]<<16 | alib_decoded[0x1f]<<24; | |
245 printf("Text section size: %x\n", offset); | |
246 printf("Region: [%s]\n", &alib_decoded[0x4c]); | |
247 #endif | |
248 | |
249 // now patch the file into RAM | |
250 offset = alib_decoded[0x18] | alib_decoded[0x19]<<8 | alib_decoded[0x1a]<<16 | alib_decoded[0x1b]<<24; | |
251 offset &= 0x3fffffff; // kill any MIPS cache segment indicators | |
252 plength = alib_decoded[0x1c] | alib_decoded[0x1d]<<8 | alib_decoded[0x1e]<<16 | alib_decoded[0x1f]<<24; | |
253 memcpy(&psx_ram[offset/4], alib_decoded+2048, plength); | |
254 | |
255 // Dispose the corlett structure for the lib - we don't use it | |
256 free(lib); | |
257 } | |
258 } | |
259 | |
260 free(file); | |
261 // free(lib_decoded); | |
262 | |
263 // Finally, set psfby tag | |
264 strcpy(psfby, "n/a"); | |
265 if (c) | |
266 { | |
267 int i; | |
268 for (i = 0; i < MAX_UNKNOWN_TAGS; i++) | |
269 { | |
270 if (!strcasecmp(c->tag_name[i], "psfby")) | |
271 strcpy(psfby, c->tag_data[i]); | |
272 } | |
273 } | |
274 | |
275 mips_init(); | |
276 mips_reset(NULL); | |
277 | |
278 // set the initial PC, SP, GP | |
279 #if DEBUG_LOADER | |
280 printf("Initial PC %x, GP %x, SP %x\n", PC, GP, SP); | |
281 printf("Refresh = %d\n", psf_refresh); | |
282 #endif | |
283 mipsinfo.i = PC; | |
284 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
285 | |
286 // set some reasonable default for the stack | |
287 if (SP == 0) | |
288 { | |
289 SP = 0x801fff00; | |
290 } | |
291 | |
292 mipsinfo.i = SP; | |
293 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo); | |
294 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo); | |
295 | |
296 mipsinfo.i = GP; | |
297 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo); | |
298 | |
299 #if DEBUG_LOADER && 1 | |
300 { | |
301 FILE *f; | |
302 | |
303 f = fopen("psxram.bin", "wb"); | |
304 fwrite(psx_ram, 2*1024*1024, 1, f); | |
305 fclose(f); | |
306 } | |
307 #endif | |
308 | |
309 psx_hw_init(); | |
310 SPUinit(); | |
311 SPUopen(); | |
312 | |
313 lengthMS = psfTimeToMS(c->inf_length); | |
314 fadeMS = psfTimeToMS(c->inf_fade); | |
315 | |
316 #if DEBUG_LOADER | |
317 printf("length %d fade %d\n", lengthMS, fadeMS); | |
318 #endif | |
319 | |
320 if (lengthMS == 0) | |
321 { | |
322 lengthMS = ~0; | |
323 } | |
324 | |
325 setlength(lengthMS, fadeMS); | |
326 | |
327 // psx_ram[0x118b8/4] = LE32(0); // crash 2 hack | |
328 | |
329 // backup the initial state for restart | |
330 memcpy(initial_ram, psx_ram, 2*1024*1024); | |
331 memcpy(initial_scratch, psx_scratch, 0x400); | |
332 initialPC = PC; | |
333 initialGP = GP; | |
334 initialSP = SP; | |
335 | |
336 mips_execute(5000); | |
337 | |
338 return AO_SUCCESS; | |
339 } | |
340 | |
341 void spu_update(unsigned char* pSound,long lBytes) | |
342 { | |
343 memcpy(spu_pOutput, pSound, lBytes); | |
344 } | |
345 | |
346 int32 psf_gen(int16 *buffer, uint32 samples) | |
347 { | |
348 int i; | |
349 | |
350 for (i = 0; i < samples; i++) | |
351 { | |
352 psx_hw_slice(); | |
353 SPUasync(384); | |
354 } | |
355 | |
356 spu_pOutput = (char *)buffer; | |
357 SPU_flushboot(); | |
358 | |
359 psx_hw_frame(); | |
360 | |
361 return AO_SUCCESS; | |
362 } | |
363 | |
364 int32 psf_stop(void) | |
365 { | |
366 SPUclose(); | |
367 free(c); | |
368 | |
369 return AO_SUCCESS; | |
370 } | |
371 | |
372 int32 psf_command(int32 command, int32 parameter) | |
373 { | |
374 union cpuinfo mipsinfo; | |
375 uint32 lengthMS, fadeMS; | |
376 | |
377 switch (command) | |
378 { | |
379 case COMMAND_RESTART: | |
380 SPUclose(); | |
381 | |
382 memcpy(psx_ram, initial_ram, 2*1024*1024); | |
383 memcpy(psx_scratch, initial_scratch, 0x400); | |
384 | |
385 mips_init(); | |
386 mips_reset(NULL); | |
387 psx_hw_init(); | |
388 SPUinit(); | |
389 SPUopen(); | |
390 | |
391 lengthMS = psfTimeToMS(c->inf_length); | |
392 fadeMS = psfTimeToMS(c->inf_fade); | |
393 | |
394 if (lengthMS == 0) | |
395 { | |
396 lengthMS = ~0; | |
397 } | |
398 setlength(lengthMS, fadeMS); | |
399 | |
400 mipsinfo.i = initialPC; | |
401 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
402 mipsinfo.i = initialSP; | |
403 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo); | |
404 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo); | |
405 mipsinfo.i = initialGP; | |
406 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo); | |
407 | |
408 mips_execute(5000); | |
409 | |
410 return AO_SUCCESS; | |
411 | |
412 } | |
413 return AO_FAIL; | |
414 } | |
415 | |
416 int32 psf_fill_info(ao_display_info *info) | |
417 { | |
418 if (c == NULL) | |
419 return AO_FAIL; | |
420 | |
421 strcpy(info->title[1], "Name: "); | |
422 sprintf(info->info[1], "%s", c->inf_title); | |
423 | |
424 strcpy(info->title[2], "Game: "); | |
425 sprintf(info->info[2], "%s", c->inf_game); | |
426 | |
427 strcpy(info->title[3], "Artist: "); | |
428 sprintf(info->info[3], "%s", c->inf_artist); | |
429 | |
430 strcpy(info->title[4], "Copyright: "); | |
431 sprintf(info->info[4], "%s", c->inf_copy); | |
432 | |
433 strcpy(info->title[5], "Year: "); | |
434 sprintf(info->info[5], "%s", c->inf_year); | |
435 | |
436 strcpy(info->title[6], "Length: "); | |
437 sprintf(info->info[6], "%s", c->inf_length); | |
438 | |
439 strcpy(info->title[7], "Fade: "); | |
440 sprintf(info->info[7], "%s", c->inf_fade); | |
441 | |
442 strcpy(info->title[8], "Ripper: "); | |
443 sprintf(info->info[8], "%s", psfby); | |
444 | |
445 return AO_SUCCESS; | |
446 } |