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).
edited 3:52 PM EST January 24, 2020
update by almendaz at 6:21 PM EST on February 18, 2020
I have been busy offline, now I take the time to post. An important note: the above code only works on the GAME.DAT file that OP uploaded (certainly NOT the NTSC versions from redump).
For these versions, the MUSSTART and MUSEND lines should be: ###
# For NTSC-U 'GAME.DAT' set MUSSTART long 0x1c78b000 set MUSEND long 0x24d06000
# For NTSC-J 'GAME.DAT' set MUSSTART long 0x1cdb9000 set MUSEND long 0x24454000
###
In any case, anyone with the game files can manually obtain those offset pretty easily: MUSSTART: offset of the FIRST ocurrence of [78 00 00 00 00 10 00 00] qword. ## 2 words, to avoid FalsePstv. MUSEND: offset of byte-array [00 00 02 00 48 49 54 20 11 00 00 00 30 01 00 00], minus 0x1800 (decimal 6144).
Or if one wants an all-version .BMS script, just replace these lines of the script
##### set MUSSTART long 0x1ce7f800 set MUSEND long 0x253fa800 #####
This new code should work on any .DAT version, assuming the last CHUNK of music is the same for all versions (by manual examination of .DAT file; the size of that chunk is 6144 bytes). Because of the search process, now the .bms will run slower, so it's preferred to obtain those values from hex editor and manually modify them on the original script.
The track names are in the main PS2 executables, the first being "sqm/sel_in.ams". Even better, they give hint of VFS, so the names corresponding to the tracks should be sorted already. A simple rename's script and the extracts are in their correct names. I appended .pcm to the .ams in order to be playable with vgmstream and the included (corrected) .txth:
##### codec = PSX channels = 2 interleave = 0x8000 sample_rate = (@0x4$4)*48000/4096 ## from so called DVD "pitch" start_offset = 0x800 ## after header data_size = 2*(@0x8$4) ## using header info num_samples = data_size #####
The two rip versions share almost the same tracks, except for exclusives, 4 in the JP-ver, 2 (one repeated 5 times) for US-ver. In fact, the many JP-exclusives are replaced with 2 exclusives for the US release.
There is also a stray se130.ams extract, that should belong to sound effects. I left it because it was in the extraction output, and also in the \sqm folder in the filesystem.
I used vgmt video demultiplexer for the MOVIE intros. I now upload the two sets.
I do not call these rips "proper", because I did a data transformation (the "de-scrambling" process), even if it's lossless. I wonder if there are other PS2 games where music has this manner of binary reorganization/scrambling.