file deinterleaver (new version)
Split files into alternating blocks of the same size. Used when manipulating audio formats with more than one channel. E.g. stereo wave streams have an interleave of 2 bytes, i.e. each two bytes the channel information switches 2xL,2xR,2xL and so on. The blocksize of this structure would be 4 (two times the interleave size). If the stream has four channels, the interleave would stay at 2, but the blocksize would be 8. So if you split the channels you need to deinterleave the file and this script does exactly that, according to the parameters you set.
Additionally you can specify a SKIP variable, which denotes an area at the start of each block not to process during the deinterleaving. A good example is the "disguised" Playstation ADPCM format in some Electronic Arts PS2 games, where some dummy marker is set each block. So, just set the layer count to one and adjust the SKIP variable.
This is an extremely powerful script! Play around with different files to get the idea what you can do with this. Most common use is channel splitting, but you can do all kinds of adjustments to your files. Easiest example would be to split audio formats into mono channels, splitting multichannel files into stereo pairs or deleting regularly occurring chunks of data inside a file.
This is a long overdue update of my old deinterleave script
, which was rather cryptic and above all really really slow. This new one boosts the running time x300 and has some additional options:
- you can choose to add the original header to the deinterleaved files
- the header can be manipulated
- the variables are now better to understand (just header, blocksize, interleave size, layer and skip)UPDATE 2016-05-16
The script now supports incomplete last blocks! Here's a little example
- header of 0x10 bytes
- four channels
- 4 byte dummy each 0x14 bytes
- you want to split the channels and know that one complete block is 0x14 bytes
Variables to set:
- HEADER 0x10
- SKIP 4
- LAYERS 4
- BLOCKSIZE 0x14 (alternatively BLOCKSIZE 0 and INTSIZE 4)
- to add the original header to each deinterleaved file, set PRESERVE to 1
- leave ADJUST at 0 if you're not familiar with QuickBMS
Let's say we have the same file, but the dummy occur for every channel interleave block. Then we have to run the script two times:
- first run, delete the dummy bytes: HEADER 0x10, PRESERVE 1, SKIP 4, LAYERS 1, BLOCKSIZE 0, INTSIZE 0x14 (or BLOCKSIZE 0x50) -> produces one smaller file
- second run, deinterleave channels: HEADER 0x10, PRESERVE 1, SKIP 0, LAYERS 4, BLOCKSIZE 0x40 (or 0 and INTSIZE 0x10) -> produces four files which are exactly 1/4th of the above file
# deinterleave file by different parameters
# (c) 2016-05-16 by AlphaTwentyThree of XeNTaX
# HEADER - area which is untouched by the deinterleaving
# PRESERVE 0/1 - set to 1 to write the skipped area from
# HEADER to each deinterleaved file
# ADJUST 0/1 - if the header needs to be adjusted, set
# this to 1 and write your code to the function
# "adjustheader" at the end of this script
# SPLIT_LAST_BLOCK 0/1 - set to 1 to split an incomplete last block equally
# between layers. If set to 0, the script will ter-
# minate if it finds an incomplete last block.
# HANDLE WITH CARE!
# BLOCKSIZE - size of one complete interleave block
# LAYERS - the numbers of (equal-sized) files you want
# to deinterleave to
# SKIP - number of bytes to skip at the start of each block
# split channels of stereo wave file: # HEADER 0x2c, PRESERVE 1, ADJUST 1 (adjust function), BLOCKSIZE 4, LAYERS 2, SKIP 0
# leave out 2 bytes each 0x10 bytes: # BLOCKSIZE 0x10, LAYERS 1, SKIP 2
# split channels of Playstation ADPCM file: # HEADER 0x2c, PRESERVE 1, ADJUST 1 (adjust function), BLOCKSIZE 2*Interleave, SKIP 0
set HEADER 0xe0 # zero if skip is at end of block, otherwise = first skip at start
set PRESERVE 0
set ADJUST 0
set SPLIT_LAST_BLOCK 1
set BLOCKSIZE 0 # size of one complete block
set INTSIZE 0x5800 # if BLOCKSIZE is set to 0, the interleave size is taken to calculate the blocksize
set LAYERS 2
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"
if INTSIZE == 0
xmath INTSIZE "BLOCKSIZE / LAYERS"
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
# 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..."
# 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."
print "ERROR: file size minus header isn't dividable by blocksize! Aborting..."
# test 3: ASIZE-HEADER-BLOCKSIZE must be greater null (at least one deinterleave cycle)
get TEST asize
xmath TEST "TEST - HEADER - BLOCKSIZE"
if FSIZE <= 0
print "Error: file too small to deinterleave! Aborting..."
xmath PSIZE "CYCLES * WSIZE + LASTINT"
if PRESERVE == 1
math PSIZE += HEADER
getDstring HDATA HEADER
for i = 1 <= LAYERS
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
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"
for k = 1 <= CYCLES
getDstring DUMMY BIAS_A
getDstring WDATA WSIZE
putDstring WDATA WSIZE MEMORY_FILE
getDstring DUMMY BIAS_B
if LASTBLOCK != 0
getDstring DUMMY RES_BIAS_A
getDstring WDATA LASTINT
putDstring WDATA LASTINT MEMORY_FILE
getDstring DUMMY RES_BIAS_B
get SIZE asize MEMORY_FILE
if ADJUST == 1
callfunction adjustheader 1
log NAME 0 SIZE MEMORY_FILE
putVarChr MEMORY_FILE 0x10 1 long
get SSIZE asize MEMORY_FILE
math SSIZE -= HEADER
putVarChr MEMORY_FILE 0x24 SSIZE long
If you like what you see, why not click the little Thank You
It will definitely motivate me!
And here's Mr.Mouse's Facebook link: http://www.facebook.com/permalink.php?s ... 8469022795