Seems like music can be played if you cut GAME.DAT somewhere at 500000000 bytes with HxD and put it in MFAudio, Interleave is 8000 bytes, but since i didn't tried to cut it in correct point playback is glitched. If someone smarter can look at this archive one more time with that info maybe they will work something out with that info. This is probably CRI ADX since game files have CRI_ADXI.IRX module, which is used for that format. Maybe it is possible to cut that .dat to a set of .adx files.
I hope you are still here after those 4 years @DCX.
I have been experimenting with this file a bit. So, rename "GAME.DAT" to "GAME.DAT.pcm", then create a file "GAME.DAT.pcm.txth" (or just ".pcm.txth", note the leading dot), and add the following parameters in the .TXTH file:
The music in GAME.DAT when played seems to jump here and there, like 1 second (?) is start-track, then 1-sec is track finisher, then the next 1-sec is 2nd portion, then 1-sec is penultimate portion... like tracking around a circle or spiral. The last audible audio would be the middle portion of track. A proper rip would require separating the 1-sec 2-ch samples & rearranging them in position, so it's NOT properly rippeable, it would need some de-scrambling to make out the music.
The audio data has [78 00 00 00 00 10 00 00] "headers" of size 0x800, just starting each track portion, this may be taken as splitting points. (Should be added to vgmstream as a custom stream? i dunno, some other games might have this type of "spiral" playback.)
In the meantime I have conceived a C++like pseudocode to make playback, maybe extracting a de-scrambled stream. The tracks must be extracted beforehand, using [78 00 00 00 00 10 00 00] as string cut-point. (Disclaimer: I'm not expert in coding, so forgive me the sintax)
Treating with INT data types
/// for each [file] in {extracted & splitted}
get filesize FSZ # some operation to get filesize here!
STRMSZ = FSZ -0x800 # stream size NCHNK = STRMSZ/0x10000 # number of "2 * interleave.size" chunks, where interleave.size (ILVSZ) = 0x8000 stream ZZZ = [] # null stream, cummulative (not sure if it's right initialization) ## maybe those "0x10000" could be replaced with "2*ILVSZ", where ILVSZ (interleave size) is defined
IDX1 = 0 IDX2 = NCHNK-1 #initial chunk indexes
while (IDX1 < IDX2) S1 = playxtr(IDX1) # worker function that extracts/plays the stream for selected chunks S2 = playxtr(IDX2) stream output ZZZ += S1 + S2 # the output stream, would require file operations IDX1++ # to start next in following start-chunk IDX2-- # to end next in previous end-chunk end
if (IDX1 == IDX2) # when NCHNK is odd number S3 = playxtr(IDX1) stream output ZZZ += S3 end
close stream ZZZ #Program ends here
function SSS = playxtr(IDX) ## stream-like function return stream SSS: offset(IDX) ... offset(IDX+0x10000) ## Stream SSS is bytes from offset "offset(IDX)" to offset "offset(IDX+0x10000)" of [file] ## Equivalently, SSS is bytes from offset "offset(IDX)" of [file], with size 0x10000 end function
function P = offset(IDX) return (0x800 + IDX*0x10000) # position in file/stream end function
/// next [file] Pseudocode corrections welcomed!
Someone out here could figure out a BMS script for this, or implement this kind of playback in vgmstream, provided the music files are extracted first.
for IDX=0...(NCHK-1), +2 # increments of 2 SSS = playxtr(IDX) stream output ZZZ += SSS end if (NCHK is odd) then NCHK = NCHK-1 #old NCHK never reused ## how to do odd/even check ?? for IDX=(NCHK-1) ...1, -2 # decrements of 2 SSS = playxtr(IDX) stream output ZZZ += SSS end
close stream ZZZ ### stream finalization
function SSS = playxtr(IDX) ## stream-like function return stream SSS: offset:= offset(IDX), size:= 0x10000 end function
function P = offset(IDX) return (0x800 + IDX*0x10000) ## position in file/stream end function
/// next [file] ************************************************
I tracked down some music information in memory if it helps anyone. The rest of the proper information (loop points, sample rate, data size) might be read by IOP memory. Memory addresses below are for the Japanese version.
menu_in.ams (menu music): 0049A074 loop segment if 0x2 0049A078 volume? 0049A07C # of loops for segment before second part plays 0049A080 file name
current music: 005A5E70 loop segment if 0x2 005A5E74 volume? 005A5E78 # of loops for segment before second part plays 005A5E7C file name
function 001BBAC0 seems to process these music variables and other stuff.
Thank you punk7890-2 for this info - I got a pretty idea of what the game does with the music, plus those findings could be implemented in vgmstream, hopefully.
I took the effort to do some analysis to the header, plus examination on the contained streams, in order to create the BMS script annexed below.
The file "GAME.DAT" has some recogniceable data in it: @ 0 ... : some data, graphics, etc etc @ 0x1ce7f800 : 1st "header" of "music" / start of "music" @ 0x253fa800 : end of "music" / start of other data / NOT-music definitely! / many trailing 0x0 near end
The "music" part has the following structure: [header(0)] [s.stream(0)] [header(1)] [s.stream(1)] [header(2)] [s.stream(2)] ... [header(n)] [s.stream(n)]
"header(ii)" is size 0x800, the first 0x10 bytes have the following form: [78 00 00 00] [00 10 00 00] [ZZ ZZ ZZ ZZ] [XX XX XX XX] where { [ZZ] } := stream.size.proper /2 and { [XX] } := stream.size / 0x20000 ( 0x20000 might be 2*interleave.size*num.channels ) Rest of header is padded with 0x0.
"s.stream(ii)" are the SCRAMBLED streams. AT LEAST they are proximal to the same file (so the tracks are not SPLITTED throughout the music bytes).
stream.size.proper is the data size of the PROPER stream; stream.size is the data size of the PADDED stream (to complete multiple of 0x20000), the padded stream contains 0x0 representing silence or maybe separators (some are exactly 0x10000 bytes of size). The [XX XX XX XX] bytes are used to get the number of chunks that form the full file stream, and thus their file size. For .txth construction, stream.size.proper := 2* [ZZ ZZ ZZ ZZ] is needed.
With this info I went to implement the pseudocode I gave earlier in BMS. Main assumptions are start/ending offsets of music part, known interleave, and the plugin format.
open FDDE DAT 0 set HDRSZ long 0x800 set ILVSZ long 0x8000 set NUMCH long 2 xmath CNKSZ "NUMCH * ILVSZ" set MUSSTART long 0x1ce7f800 set MUSEND long 0x253fa800
set POS0 long MUSSTART append ## findloc POS0 binary \x78\x00\x00\x00\x00\x10\x00\x00 ## search [78 00 00 00 00 10 00 00] set FILENUM int 0
do
set FNAME string "" if (FILENUM < 10) string FNAME + "0" endif string FNAME + FILENUM string FNAME + ".pcm" ## .ams does NOT play/ breaks player
log FNAME POS0 HDRSZ
xmath NNPOS "POS0 + 0xC" goto NNPOS get NN long xmath NUMCHK "2 * NN" xmath STRMSZ "NUMCHK * CNKSZ " xmath FILESZ "HDRSZ + STRMSZ" xmath NUMCHK2 "NUMCHK"
You put this text in a .bms text file, save it, then run it with quickbms, together with input file "GAME.DAT". Output should be de-scrambled stream files: 00.pcm,01.pcm,...53.pcm, with their 0x800 headers. The ".pcm.txth" file that should acompany these .pcm files should have this content:
codec = PSX ## ams (ar1ka music stream??) channels = 2 interleave = 0x8000 sample_rate = 48000 start_offset = 0x800 ## after header data_size = 2*(@0x8$4) ## using header info num_samples = data_size
Notes: extract #29 has bad info for looping/repeat, the sample number seems not correct. Also, #39 seems tiny bit early in repeat point. Unfortunately .ams extension breaks the player, so I renamed to .pcm instead (maybe this extension could be added to vgmstream with the info I posted).