Star Trek: Conquest (Wii) - Music.WSB/.WSS

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

Can somebody take a look at this archive type and maybe write a script to extract it That would be awesome! :)
https://mega.nz/#!Oh8WmZaB!NUbV8Hc0Nl-2 ... WqN8IwSNFA
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

No ideas? :\
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by aluigi »

http://aluigi.org/bms/stc_wsb_wss.bms
This is not my field but I suspect that those 32bytes handled by the script as COEFF may be the coefficient data used in Nintendo adpcm... anyway now it's your job :)
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

All streams have a looped section and an intro section. The problem is that the number of samples is the same for both of these, which is obviously wrong but it's saved like this in the header. The correct nos is nowhere to be found. The offsets have to be corrected by +0x80 in order for the streams to work. Also, there was a little mistake in your script: you wrote i+1 but didn't write i-1 afterwards. ;)
So well, here's my script that automatically adds genh headers. The streams all work (mono though) but of course the intro sections are missing the correct number of samples.

Code: Select all

old script erroneous, corrected script pending
Last edited by AlphaTwentyThree on Mon May 30, 2016 11:49 am, edited 1 time in total.
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

I just noticed that the files aren't played correctly, so we'll wait till I've figured out how to deal with them
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

Ok, I essentially know how the system works. Actually those "intro" files are the first interleave block of a stereo file. So 1/2, 3/4 and so on belong together with size(1) being the stereo interleave. I'll implement it tonight.
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

Tested manually and it works. Implentation following...
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by AlphaTwentyThree »

OH. MY. GOD! What a hazzle to get all the things working. It was actually more complicated than I thought. The section starting at 0x324 in the wsb file actually contains a list of parts that belong together, so in this case it's either mono or stereo. The FILES variable is actually the PARTS variable (0x4a) and the file number is at 4 in the wsb (0x26). There are two mono files that have 0xcdcdcdcd as their second part, so that's the identifier.
I didn't want to put everything in one script because that would be too confusing. Instead, I merged the parts that belong together and created a pseudo-header that depicts the channels, number of samples, frequency and one or two decoding coefficients. The second script either makes a simple mono GENH if the file is mono and for the stereo files, well, a re-interleave: Deinterleaving the whole stream with the given interleave (in this case the size of the first part), re-interleaving it and adding a genh header.
So, without further ado, here are both scripts:

Code: Select all

# Star Trek: Conquest (WSB/WSS)
# script for QuickBMS http://quickbms.aluigi.org
# base written by Aluigi - thanks! :)
# corrections written by AlphaTwentyThree
# note that the extracted files only have a pseudo-header and need to be processed further

open FDDE "WSB"
open FDDE "WSS" 1

endian big
goto 0x4
get FILES long
goto 0xc
get PARTS long # entries / file parts
xmath INFO "0x14 * FILES + 0x30"
goto INFO
for i = 0 < FILES
   get PART1 long
   get PART2 long
   getDstring DUMMY 0x1c
   putArray 0 i PART1
   putArray 1 i PART2
next i

for i = 0 < FILES
   getArray PART2 1 i
    get OFFSET1 long
   savepos DAT1
   getDstring H1 0x3c
   savepos MYOFF
   get OFFSET2 long
   savepos DAT2
   xmath SIZE1 "OFFSET2 - OFFSET1"
   getDstring H2 0x3c
   if PART2 != 0xcdcdcdcd # stereo
      set CH 2
      savepos MYOFF
   else # mono file
      set CH 1
      set OFFSET2 0
      set DAT2 0
      set SIZE2 0
   endif
   xmath n "i + 1"
   if n != FILES
      get SIZE2 long
      goto MYOFF
   else
      get SIZE2 asize 1
   endif
   math SIZE2 -= OFFSET2
   xmath PSIZE "SIZE1 + SIZE2 + CH * 0x3c + 4"
   putVarChr MEMORY_FILE PSIZE 0
   log MEMORY_FILE 0 0
   putVarChr MEMORY_FILE 0 SIZE1 long # interleave or stream size
   putVarChr MEMORY_FILE 4   CH long # channels
   append
   log MEMORY_FILE DAT1 0x3c
   if CH == 2
      log MEMORY_FILE DAT2 0x3c
   endif
   log MEMORY_FILE OFFSET1 SIZE1 1
   if CH == 2
      log MEMORY_FILE OFFSET2 SIZE2 1
   endif
   append
   get SIZE asize MEMORY_FILE
   get NAME basename
   string NAME p= "%s_%d.mus" NAME i
   log NAME 0 SIZE MEMORY_FILE
next i


The tricky but imaginative part is the savepos MYOFF at line 30. It is only overwritten in line 37 if the file is stereo. Otherwise the read data is discarded and the sizes for the second part set to zero. So the goto MYOFF in line 47 changes if the file is stereo or mono.
Also note the nifty little trick in the calculation of the preallocation size at line 52 where I just multiplied the 0x3c part with the channel count. :) (note that if the channels are 1, then SIZE2 is zero and doesn't add to the preallocation size).

And here's the second script to convert the mus files to playable genh:

Code: Select all

# Star Trek: Conquest 
# converts *.mus with pseudo-headers to playable GENH files
# written by AlphaTwentyThree of Zenhax
# script for QuickBMS http://quickbms.aluigi.org

endian big
get INTSIZE long
get CH long
get NOS long
get DUMMY long
get FREQ long
savepos OFF_COEFF1
getDstring DUMMY 0x30
if CH == 2
   getDstring DUMMY 0xc
   savepos OFF_COEFF2
   set HEADER 0x80
elif CH == 1
   set OFF_COEFF2 OFF_COEFF1
   set HEADER 0x44
endif
set INTERLEAVE 4
endian little
if CH == 2
   set LAYERS 2
   set SPLIT_LAST_BLOCK 1
   set BLOCKSIZE 0

   xmath BLOCKSIZE "(INTSIZE * LAYERS)"
   set WSIZE INTSIZE
   get CYCLES asize
   xmath CYCLES "(CYCLES - HEADER) / BLOCKSIZE"

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

   callfunction deinterleave 1

else
   log MEMORY_FILE2 0 0
   log MEMORY_FILE3 0 0
endif
callfunction GENH 1
if CH == 2
   callfunction reinterleave 1
else
   get SIZE asize
   math SIZE -= HEADER
   append
   log MEMORY_FILE HEADER SIZE
   append
endif

get SIZE asize MEMORY_FILE
get NAME basename
string NAME += ".genh"
log NAME 0 SIZE MEMORY_FILE

startfunction deinterleave
   xmath PSIZE "CYCLES * WSIZE + LASTINT"
   for i = 1 <= LAYERS
      if i == 1
         putVarChr MEMORY_FILE2 PSIZE 0
         log MEMORY_FILE2 0 0
      elif i == 2
         putVarChr MEMORY_FILE3 PSIZE 0
         log MEMORY_FILE3 0 0
      endif
      xmath BIAS_A "(i - 1) * WSIZE" # bias at start
      xmath BIAS_B "BLOCKSIZE - BIAS_A - WSIZE" # bias at end
   
      xmath RES_BIAS_A "(i - 1) * LASTINT"
      xmath RES_BIAS_B "LASTBLOCK - RES_BIAS_A - LASTINT"
      goto HEADER
      
      for k = 1 <= CYCLES
         getDstring DUMMY BIAS_A
         getDstring WDATA WSIZE
         if i == 1
            putDstring WDATA WSIZE MEMORY_FILE2
         elif i == 2
            putDstring WDATA WSIZE MEMORY_FILE3
         endif
         getDstring DUMMY BIAS_B
      next k
      if LASTBLOCK != 0
         getDstring DUMMY RES_BIAS_A
         getDstring WDATA LASTINT
         if i == 1
            putDstring WDATA LASTINT MEMORY_FILE2
         elif i == 2
            putDstring WDATA LASTINT MEMORY_FILE3
         endif
         getDstring DUMMY RES_BIAS_B
      endif
   next i
endfunction

startfunction GENH
   get SIZE1 asize MEMORY_FILE2
   get SIZE2 asize MEMORY_FILE3
   xmath SIZE "SIZE1 + SIZE2" # stream size
   xmath PRE_SIZE "SIZE + 0xc0"
   putVarChr MEMORY_FILE SIZE 0
   log MEMORY_FILE 0 0

   putVarChr MEMORY_FILE 0 0x484e4547 long # "GENH"
   putVarChr MEMORY_FILE 4 CH long # ch
   putVarChr MEMORY_FILE 8 INTERLEAVE long # interleave
   putVarChr MEMORY_FILE 0xc FREQ long
   putVarChr MEMORY_FILE 0x10 0xffffffff long
   putVarChr MEMORY_FILE 0x14 NOS long # number of samples
   putVarChr MEMORY_FILE 0x18 0xc long # ?
   putVarChr MEMORY_FILE 0x1c 0xc0 long # stream start
   putVarChr MEMORY_FILE 0x20 0xc0 long # stream start
   putVarChr MEMORY_FILE 0x24 0x80 long # coeff1
   putVarChr MEMORY_FILE 0x28 0xa0 long # coeff2
   putVarChr MEMORY_FILE 0x2c 1 long
   putVarChr MEMORY_FILE 0x34 0x80 long # coeff1
   putVarChr MEMORY_FILE 0x38 0xa0 long # coeff2
   putVarChr MEMORY_FILE 0x7f 0 byte
   append
   log MEMORY_FILE OFF_COEFF1 0x20
   log MEMORY_FILE OFF_COEFF2 0x20
   append
endfunction

startfunction reinterleave
   get LOOPS asize MEMORY_FILE2
   xmath LOOPS "LOOPS / INTERLEAVE"
   set OFFSET 0
   for i = 1 <= LOOPS
      goto OFFSET MEMORY_FILE2
      getdstring VAR INTERLEAVE MEMORY_FILE2
      putdstring VAR INTERLEAVE MEMORY_FILE
      goto OFFSET MEMORY_FILE3
      getdstring VAR INTERLEAVE MEMORY_FILE3
      putdstring VAR INTERLEAVE MEMORY_FILE
      math OFFSET += INTERLEAVE
   next i
endfunction
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: Star Trek: Conquest (Wii) - Music.WSB/.WSS

Post by aluigi »

Excellent job :D