ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Sun Sep 24, 2017 1:33 am

All times are UTC




Post new topic  Reply to topic  [ 2 posts ] 
Author Message
PostPosted: Thu Sep 14, 2017 12:37 pm 

Joined: Sat Aug 09, 2014 11:21 am
Posts: 607
Hello there!

I'm currently ripping the music of PSX games and for this matter, I've written some scripts to help me do this. I will post the scripts I have here and update when I write new ones.

First of all, you'll need an ISO browser that lets you extract XA (audio) and STR (video) files. For this purpose I'm using IsoBuster (https://www.isobuster.com/) with the "extract RAW" option.

Second, here are two scripts that will process those two file types

1. unecm

http://www.theisozone.com/downloads/pla ... ols/unecm/
Tool to decompress ecm files often used in PSX images.


2. XA deinterleaver & splitter

Just as it sounds. Automatically extracts all the streams out of interleaved XA files. I've implemented various types of split and end markers to support plenty of XA variants. If you find one that doesn't work with this, please post here.
You can manually overwrite the layer count and prevent the splitting/silence cutting of the layers. The scripts also adds a CDXA header so you can listen to the result. This is mainly for developer reasons.
Practical: If you set LAYERS to 1 and leave NOSPLIT at 0 you can add a CDXA header to a headerless CDXA stream. The silence at the end is automatically removed.

Code:
# deinterleaves and splits RAW-extracted XA files 
# rev 2017-09-20
# to playable XA files with CDXA header
# written by AlphaTwentyThree of Zenhax
# script for QuickBMS http://quickbms.aluigi.org

idstring \x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF
callfunction get_layers 1
#set LAYERS 1
#print "layers: %LAYERS%"
set NOSPLIT 0 # set this to 1 to prevent splitting of all layers

xmath BLOCKSIZE "0x930 * LAYERS"
get CYCLES asize
math CYCLES /= BLOCKSIZE
callfunction deinterleave

startfunction get_layers
   set OFFSET 0x11
   math OFFSET += 0x930
   goto OFFSET
   get START byte # actually second one as 0 repeats
   math OFFSET += 0x930
   xmath GO "START + 1"
   for i = GO
      goto OFFSET
      get TEST byte
      if TEST == START
         break
      endif
      math OFFSET += 0x930
   next i
   xmath LAYERS "i - START"
endfunction
   
startfunction deinterleave
   set CUT_SILENCE 1
   xmath PSIZE "CYCLES * 0x930"
   get BNAME basename
   for i = 1 <= LAYERS
      set SINGLE 1
      putVarChr MEMORY_FILE PSIZE 0
      log MEMORY_FILE 0 0
      xmath JUMPOFFSET "(i-1)*0x930"
      for k = 1 <= CYCLES
         goto JUMPOFFSET
         getDstring WDATA 0x930
         putDstring WDATA 0x930 MEMORY_FILE
         math JUMPOFFSET += BLOCKSIZE
      next k
      if NOSPLIT == 1
         set SINGLE 1
         set SIZE PSIZE
      else
         set m 1 # 1 segment start
         callfunction get_segments 1
      endif
      if SINGLE == 1
         set OFFSET 0
         if SIZE != 0
            if NOSPLIT != 1
               if CUT_SILENCE != 0
                  callfunction cut_silence 1
               endif
            endif
            callfunction CDXA 1
            string NAME p= "%s_%i.xa" BNAME i
            get SIZE asize MEMORY_FILE2
            log NAME 0 SIZE MEMORY_FILE2
         endif
      else
         print "found %m% segments in layer %i%"
         set c 1
         for n = 1 <= m # walk through array with segment TOC
            getArray OFFSET 0 n
            getArray SIZE 1 n
            if SIZE != ""
               callfunction CDXA 1
               string NAME p= "%s_%i_%i.xa" BNAME i c
               get SIZE asize MEMORY_FILE2
               log NAME 0 SIZE MEMORY_FILE2
               math c += 1
               putArray 0 n "" # IMPORTANT!!!
               putArray 1 n ""
            endif
         next n
      endif
   next i
endfunction

startfunction get_segments
   set SEARCH 0x12
   xmath LAYER_CYCLES "PSIZE / 0x930"
   set ACTIVE 1 # to determine if a new start is needed
   set OFFSET 0
   set SILENCE_CUT 0
   for l = 1 <= LAYER_CYCLES
      goto SEARCH MEMORY_FILE
      get TEST byte MEMORY_FILE
      get TEST2 byte MEMORY_FILE
      get DUMMY long MEMORY_FILE
      get TEST3 byte MEMORY_FILE # needs to be 0x0c
      if ACTIVE == 1 # offset is set, search for new start
         if TEST == 0xe4 || TEST == 0x80 || TEST2 == 0 || TEST == 0
            callfunction enter 1
            set ACTIVE 0
            set CUT_SILENCE 0
         elif TEST == 0x48 # stream cut, stays active
            set SILENCE_CUT 1
            callfunction enter 1
            if SIZE > 0x930
               math m += 1
            endif
            xmath OFFSET "SEARCH + 0x930 - 0x12"
            set SINGLE 0
         elif TEST == 0xc2 # do nothing, jump one forward
            set ACTIVE 0
         endif
      elif ACTIVE == 0 # search new start
         if TEST == 0x64 && TEST2 != 0 && TEST3 != 0
            math m += 1
            xmath OFFSET "SEARCH - 0x12"
            set SINGLE 0 # second stream found
            set ACTIVE 1
         endif
      endif
      math SEARCH += 0x930
   next l
   if SILENCE_CUT == 1
      math m -= 1
   endif
endfunction

startfunction enter
   math SEARCH -= 0x12
   xmath SIZE "SEARCH - OFFSET"
   if SIZE > 0x930 # sometimes there's a 0x48-only marker loop at the end
      #print "SEG %m%: %SIZE% bytes @ offset %OFFSET%"
      putArray 0 m OFFSET
      putArray 1 m SIZE
   else
      putArray 0 m ""
      putArray 1 m ""
      math SEARCH += 0x930 # skip one block
      math l += 1          # <--- don't forget this!
   endif
   math SEARCH += 0x12
endfunction

startfunction cut_silence
   xmath SILENCE_CYCLES "PSIZE / 0x930"
   xmath STARTBLOCK "SILENCE_CYCLES / 5"
   xmath SIZE "STARTBLOCK * 0x930 + 0x28"
   for o = STARTBLOCK <= SILENCE_CYCLES
      goto SIZE MEMORY_FILE
      get TEST longlong MEMORY_FILE
      if TEST == 0
         break
      endif
      math SIZE += 0x930
   next o
   math SIZE -= 0x28
   if o == SILENCE_CYCLES
      math SIZE += 0x930
   endif
endfunction

startfunction CDXA
   xmath PSIZE2 "SIZE + 0x2c"
   putVarChr MEMORY_FILE2 PSIZE2 0
   log MEMORY_FILE2 0 0
   set MEMORY_FILE2 binary "\x52\x49\x46\x46\xe4\x04\xbe\x02\x43\x44\x58\x41\x66\x6d\x74\x20\x10\x00\x00\x00\x00\x00\x00\x00\x01\x55\x58\x41\x01\x00\x00\x00\x00\x00\x00\x00\x64\x61\x74\x61\xc0\x04\xbe\x02"
   xmath RIFFSIZE "SIZE + 0x24"
   putVarChr MEMORY_FILE2 0x04 RIFFSIZE long
   putVarChr MEMORY_FILE2 0x28 SIZE long
   append
   log MEMORY_FILE2 OFFSET SIZE MEMORY_FILE
   append
endfunction



3. STR audio extractor

Does what it says: extract the XA stream from an STR movie file, playable with winamp/foobar and the vgmstream plugin. At the moment, only single streams are supported.

Code:
# extracts CDXA audio from Playstation STR movie files
# rev 2017-09-14
# written by AlphaTwentyThree of Zenhax
# script for QuickBMS http://quickbms.aluigi.org

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"
get FSIZE asize
set OFFSET 0
append
DO
   set IDENT OFFSET
   math IDENT += 0x12
   goto IDENT
   get DAT byte
   if DAT == 0x64 # audio marker
      log MEMORY_FILE OFFSET 0x930
   endif
   math OFFSET += 0x930
WHILE OFFSET < FSIZE
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 += ".xa"
log NAME 0 SIZE MEMORY_FILE


4. PSound by snailrush

http://snailrush.online.fr/
This little program lets you scan archives for VAG and SS2 files to check if you'll need to extract the contents.


5. PSF by Mark Grass

http://www.romhacking.net/utilities/1020/
Tool to convert SEQ/VH/VB triplets to playable PSF files.


That's it for the moment. I will update this thread with scripts for individual games.


Top
   
PostPosted: Tue Sep 19, 2017 10:58 pm 

Joined: Sat Aug 09, 2014 11:21 am
Posts: 607
Updated the de-interleave script to support yet two more variants.


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 2 posts ] 

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Limited