Many Playstation games have interleaved XA files to save their music. Each interleaved XA file consists of exactly 8 or 16 layers (will need to add support). Each layer starts with [00FFFFFFFFFFFFFFFFFFFF001430][number byte][layer number byte][audio designator byte]. If the file is stereo, the last dword is repeated. The file interleave is always 0x930, that's the distance to each [00FFFFFFFFFFFFFFFFFFFF001430]-block. The audio designator is 0x64 if audio is present and 0x00 if the layer is empty. In this case the layer number is also 0x00. That's one of the reasons why PSX images are highly compressable.
Each of the block headers stays intact inside the stream. If a stream is finished, the last block has either the audio designator 0xE4 and all subsequent blocks have 0x48 OR the last block is normal (0x64) and all subsequent blocks have 0x00 as designator.
In some cases (take Descent II PSX for example), the track end isn't designated at all but the last few ms of the track are repeated till the end of the layer. I haven't yet found a way to cut these file correctly.
The following script deinterleaves those streams, cuts each stream at a given stop designator and adds a CDXA header. The files are playable with in_vgmstream.dll (newest release). Currently there is no "empty layer" support yet, but I'll code that later. If there's some header present before the [00FFFFFFFFFFFFFFFFFFFF001430]-block, just adjust the HEADER variable.
Code: Select all
set HEADER 0 set INTERL 0x930 set LAYERS 8 set JUMP INTERL math JUMP *= LAYERS get FSIZE asize for i = 1 <= LAYERS log MEMORY_FILE 0 0 set MEMORY_FILE binary "\x52\x49\x46\x46\xe4\x04\xbe\x02\x43\x44\x58\x41\x66\x6d\x74\x20\x10\x0\x0\x0\x0\x0\x0\x0\x1\x55\x58\x41\x1\x0\x0\x0\x0\x0\x0\x0\x64\x61\x74\x61\xc0\x4\xbe\x2" set OFFSET i math OFFSET -= 1 math OFFSET *= INTERL math OFFSET += HEADER set QUIT 0 append for set CHECK OFFSET math CHECK += 0x12 goto CHECK get DAT byte # audio marker if DAT == 0x48 set QUIT 1 elif DAT == 0xE4 set QUIT 2 elif DAT == 0 set QUIT 1 endif set TEST OFFSET math TEST += INTERL if TEST == FSIZE set QUIT 2 endif if QUIT == 0 log MEMORY_FILE OFFSET INTERL math OFFSET += JUMP elif QUIT == 2 log MEMORY_FILE OFFSET INTERL break elif QUIT == 1 break endif next append get SIZE asize MEMORY_FILE set RIFFSIZE SIZE math RIFFSIZE -= 8 set DSIZE SIZE math DSIZE -= 0x2c putVarChr MEMORY_FILE 0x04 RIFFSIZE long putVarChr MEMORY_FILE 0x28 DSIZE long get NAME basename string NAME += "_" string NAME += i string NAME += ".xa" log NAME 0 SIZE MEMORY_FILE next i