Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

[Script] GENH DSP layer splitter

Featured Replies

  • Author
  • Localization

AlphaTwentyThree, posted Sat May 21, 2016 8:50 pm (13609)


Hello fellow rippers and coders!

I have just encountered multichannel DSP files in the game "de Blob 2" for Wii. They are packed into FSB containers and were played correctly but the streams are actually layers, so a multichannel playback isn't what I was after. So I extracted the containers with Luigi's fsbext and wrote a script that automatically splits the files by layers. For this, I simply tweaked my deinterleave script a little bit to meet the requirements. Took me about 20 mins. ;)
Have fun with the script! :)
Don't forget to post a little thanks if you like this. ;)

Code:
# splits multichannel GENH dsp files into layers
# - will leave 1 and 2 channels (do nothing)
# - will split into stereo pairs if ch count is even
# - will split into mono files if ch count is odd

# script 1.01

# written by AlphaTwentyThree of XeNTaX
# script for QuickBMS http://quickbms.aluigi.org

idstring "GENH"
get CH long
if CH == 2 # stays
   cleanexit
elif CH == 1
   cleanexit
else
   xmath TEST "CH % 2"
   if TEST == 0
      set INTSIZE 4
      xmath LAYERS "CH / 2"
      set CH 2
   else
      set LAYERS CH
      set CH 1
      set INTSIZE 2
   endif
endif
goto 0x24
get COEFF_START long

goto 0x1c
get HEADER long
set PRESERVE 1
set ADJUST 1
set SPLIT_LAST_BLOCK 0
set BLOCKSIZE 0 # size of one complete block
set SKIP_START 0 # area at start of each block to skip
set SKIP_END 0 # area at end of each block to skip

if BLOCKSIZE == 0
   xmath BLOCKSIZE "(INTSIZE * LAYERS) SKIP_START SKIP_END"
endif
if INTSIZE == 0
   xmath INTSIZE "BLOCKSIZE / LAYERS"
endif

xmath WSIZE "(BLOCKSIZE - SKIP_START - SKIP_END) / LAYERS" # data to write: (BLOCKSIZE - SKIP_START - SKIP_END)/LAYERS
get CYCLES asize
xmath CYCLES "(CYCLES - HEADER) / BLOCKSIZE"

get LASTBLOCK asize
xmath LASTBLOCK "(LASTBLOCK - HEADER) % BLOCKSIZE"
xmath LASTINT "LASTBLOCK / LAYERS"

callfunction testparameters 1
get EXT extension
callfunction deinterleave

startfunction testparameters
   # test 1: (BLOCKSIZE-SKIP_START-SKIP_END)/LAYERS must be integer (one block must be dividable into skip and layers)
   xmath TEST "BLOCKSIZE - SKIP_START - SKIP_END"
   math TEST %= LAYERS # single layer -> always ok
   if TEST != 0
      print "Error: blocksize minus skip isn't dividable by layer count! Aborting..."
      cleanexit
   endif
   
   # test 2: test for incomplete last block
   get TEST asize
   math TEST -= HEADER
   math TEST %= BLOCKSIZE
   if TEST != 0
      if SPLIT_LAST_BLOCK == 1
         print "Warning: file size minus header isn't dividable by blocksize! Last block will be equally split between layers!"
         print "Last chunks will have size of %LASTINT% bytes each."
      else
         print "ERROR: file size minus header isn't dividable by blocksize! Aborting..."
         cleanexit
      endif
   endif
   
   # test 3: ASIZE-HEADER-BLOCKSIZE must be greater null (at least one deinterleave cycle)
   get TEST asize
   xmath TEST "TEST - HEADER - BLOCKSIZE"
   if FSIZE       print "Error: file too small to deinterleave! Aborting..."
      cleanexit
   endif
endfunction
   
startfunction deinterleave
   xmath PSIZE "CYCLES * WSIZE LASTINT"
   if PRESERVE == 1
      math PSIZE = HEADER
      goto 0
      getDstring HDATA HEADER
   endif
   
   
   for i = 1       putVarChr MEMORY_FILE PSIZE 0
      log MEMORY_FILE 0 0
      get NAME basename
      string NAME = "_"
      string NAME = i
      if PRESERVE == 1
         putDstring HDATA HEADER MEMORY_FILE
         string NAME = "."
         string NAME = EXT
      endif
      xmath BIAS_A "(i - 1) * WSIZE SKIP_START"# bias at start
      xmath BIAS_B "BLOCKSIZE - BIAS_A - WSIZE" # bias at end
   
      xmath RES_BIAS_A "(i - 1) * LASTINT SKIP_START"
      xmath RES_BIAS_B "LASTBLOCK - RES_BIAS_A - LASTINT"
      goto HEADER
      for k = 1          getDstring DUMMY BIAS_A
         getDstring WDATA WSIZE
         putDstring WDATA WSIZE MEMORY_FILE
         getDstring DUMMY BIAS_B
      next k
      if LASTBLOCK != 0
         getDstring DUMMY RES_BIAS_A
         getDstring WDATA LASTINT
         putDstring WDATA LASTINT MEMORY_FILE
         getDstring DUMMY RES_BIAS_B
      endif
      get SIZE asize MEMORY_FILE
      if ADJUST == 1
         xmath COEFF1 "COEFF_START (i - 1) * CH * 0x20"
         xmath COEFF2 "COEFF1 0x20"
         callfunction adjustheader 1
      endif
      log NAME 0 SIZE MEMORY_FILE
   next i
endfunction

startfunction adjustheader
   putVarChr MEMORY_FILE 4 CH long
   putVarChr MEMORY_FILE 0x24 COEFF1 long
   putVarChr MEMORY_FILE 0x34 COEFF1 long
   putVarChr MEMORY_FILE 0x28 COEFF2 long
   putVarChr MEMORY_FILE 0x38 COEFF2 long
endfunction
  • Author
  • Localization

AlphaTwentyThree, posted Sat May 21, 2016 9:12 pm (13611)


Just updated to script 1.01.
Apparently, multichannel DSP files with an odd number of channels are interleaved with 2 instead of 4.
  • Author
  • Localization

brendan19, posted Sun May 22, 2016 2:31 am (13615)


Thanks Alpha :)
  • Author
  • Localization

Mygoshi, posted Sat May 28, 2016 6:48 pm (13740)


Nice script, thanks.
Guest
This topic is now closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.