Twisted Metal 4- menu music extract by arrlson at 3:17 PM EDT on May 21, 2018
I assume it is inside /DATA/MENU/MENUVAB.MR, but cannnot extract or decode (??). I used ADPCM extract to the file /DATA/GAME.VAB & made GENH for each sample (VAG?) with 11025 Hz mono to see if menu track was there, but there was not, only sfx. MENUVAB.MR is the largest (417,688 bytes) of the .MR files present, so it could contain sound data (the name also hints to this). Here Thanks in advance.
The .MR files are compressed zlib archives. I don't have a VFS Extractor working for it, but you can still use the zlib decompressor tool in VGMToolbox. MENUVAB.MR is the file of interest.
1. Open up the file of interest (MENUVAB.VR) with any hex editor.
2. Upon inspection, the file seems to be a container as some sort of VFS.
3. A string that has a filename + extension string (menu.vab) is present near the beginning of the container... which may/may not consist of more files throughout the container.
4. After examining the particular file of interest within the VFS (menu.vab), it's noticeable that the proceeding strings show no signs of a typical header that a .vab file would normally have. This may lead to the thoughts of encryption/compression/fake extension/etc. Look through the serial ID file name located in the game's directory (SCUS_945.60) and, through examination, "Copyright 1995-1998 Mark Adler" string can be found, which can hint to the use of glib/zlib (PS: I have no idea how to differentiate between zlib and glib, so I had to trial and error offsets in VGMToolbox at this point).
5. Use zlib Compress/Decompress tool in VGMToolbox. Set to "Decompress" and set the Starting Offset to "0x40". As reference, the filename + extension string in this file is from 0x34~0x3B. Ignore the next 4 bytes "0x3C~0x3F". The next byte following that will be the starting offset "0x40".
Through this, you should have that particular .vab file uncompressed now. I attempted to make a .GENH file since it is stereo, using P.E.Op.S. Sound debug as a helper due to the lack of loop pointer/frequency information (it may even be sequenced.) I do not recommend taking this as the finished vgm file due to me guessing on the loop pointer portion (and if any other errors are present in the .GENH itself).
Thank you! P.E.Op.S. Sound seems to be very useful in these cases! With the info you obtained, I could create my own .GENH files. I compared the .genh file you provided, with the decompressed .vab file you got. If menu music is indeed stereo, then the interleave 0x1f670, which is EXACTLY half the size of the VB data in the .genh ( 0.5*[sizeof(.genh) - 0x1000] ), is ALSO the size for each of the 2 first sound samples inside .vab (except for 0x10 zero-bytes between them). Interleaving those 2 samples (adding 0x10 zero-bytes before the second) makes the stereo track. According from your picture, it could be simply streamed from the samples, not different in principle than a .SEQ playing just one note (two "instruments" in this case). I assume something similar to this occurs with TM2 & TM:SB menus? I'll inspect that -unless you're faster than me & drop them first!! :). Thank you.
@AceK: is there a way to open VAB files in the P.E.Op.S. Sound debug screen? Or did you just leave the whole game running as that track was playing (rather than the raw samples playing from a PSF or some other trickery)?
I used the game for playback via EPSXE. As mentioned, I do not recommend having this as the finished form because I am certain that the loop pointer is incorrect (and only spent roughly an hour comparing in-game + genh to see if it separates overtime with trial and error as I can't find what calculates the loop pointers).
EDIT: So the loop pointer I got (still unsure if correct, but should be pretty close) should be a LoopStart of 28 samples (LoopEnd is assumed to be EOF). I listened to the .genh I uploaded above (which was originally set to LoopStart at 24 samples)... and by 30 minutes or so of playback, it started to sound very delayed. To correct this, the value must be higher (ie: needs to be faster/shorter to match in-game loop).
I used Cheat Engine to find the loop string and used this as a base:
In-game Pointer Data via Cheat Engine: 7636D0 = Starting point 7636E0 = LoopStart 782D30 = LoopEnd/Total Sample Count
In-game Pointer Data Converted from Hex to Decimal: 7747280 = Starting Point 7747296 = LoopStart 7875888 = LoopEnd/Total Sample Count
In-game Pointer Data (Decimal) Subtracted to Match Starting Point Value "0": 0 = Starting Point 16 = LoopStart 128608 = LoopEnd/Total Sample Count
I ended up dividing the .genh (.vb) total sample count "225092" with the in-game pointer data subtraction total sample count "128608" to get a multiple value of "1.750217715849714."
I used the multiple value "1.750217715849714" to multiply the above LoopStart value from the in-game pointer data subtraction.
@AceK: Ah, okay. Was just hoping there was finally a way to get the sample rate of pure VAB samples.
As for the loop points; have you looked at the ADPCM blocks? The byte in the second column (0x01) should specify whether or not there is a loop, and where it starts/ends.
Bit 0 (mask 0x01) specifies loop end Bit 1 (mask 0x02) specifies loop existence Bit 2 (mask 0x04) specifies loop start
@Nisto - I believe that the key to proper sample rates definitely lies within the precompiled PSYQ libraries. It isn't perfect, but this might help: Link
SsPitchFromNote() is only one of many sound functions... I'm certain there are others that could be beneficial.