Takes a disc image file of Sly 2 or Sly 3 (including some of the demos), and lets you listen to (and download, raw or rendered to wav) all of its streamed music and ambient tracks.
Update 06/04/25: When a disc is loaded, you can make a .zip file containing all tracks which are currently listed on the select box (based on the filters applied with checkboxes)
Because this operation takes a lot of memory and CPU, there is a maximum limit on how many tracks you can put in a single zip file (and the page will tell you if there are too many)
If you have CPU to spare, you can bypass this limit by writing and running the phrase option_noZipLimit=true
in your browser's console (see developer tools on MDN)
No because you're not uploading anything anywhere. This page does all the work locally, in your browser (preferably Firefox), without relying on a server after it's loaded.
It's a bit like vgmstream's web player, but in pure javascript.
Update 06/04/25: However, it will take a lot of time (and memory) to make a single .zip file that contains every audio track on the disc, if you choose to do so.
Because this page is made for a specific format used in Sly 2 and 3, and I had to manually find and classify each track. These games in particular have their entire file structure hidden, so searching for them is not as easy as opening a folder and reading a name.
Yes if you put this file in the same directory and rename it ".kpv.txth" (dots are important).
Read more about vgmstream's TXTH files on their github
discIdPromise
).knownIDs
at the end of slyDiscMusic_data.js),playTrack
)renderAdpcmToWav
).Yes (see slyDiscMusic_io.js, function loadFileDataPromise
)
interpretTrackHeader
in slyDiscMusic_play.js):
Offset | Format | Value | Notes |
---|---|---|---|
0x000 | ascii string | " KPV" (0x20 0x4B 0x50 0x56) | |
0x004 | Uint32 LE | length : number of used bytes per channel | each channel occupies an integer number of 0x800 sectors, so this value should be accordingly rounded up to get the actual file size |
0x008 | Uint32 LE | unknown (sector size?): always 0x800 | |
0x00C | Uint32 LE | interleave*2 : double of channel interleave | Usually 0x2000, meaning that channels alternate every 0x1000 bytes. |
0x010 | Uint32 LE | sampleRate | |
0x014 | Uint32 LE | channels | |
0x018 | byte⁠[channels]⁠[4] | channel mapping | see below |
0x7FC | Uint32 LE | loop : byte offset of loop start point in each channel | this single value is all the way to the end of the disc sector, separate from the rest of the header |
Byte 0 | Byte 1 | Uint16 LE |
---|---|---|
0x7F | Layer number | 0x0000 for Mono layers,0x005A and 0x010E to couple 2 channels into a Stereo layer |
psxApcmDecoder
in streamGen.js, based on vgmstream implementation)Byte 0 | Byte 1 | Bytes 2...15 |
---|---|---|
Low Nibble: shift High Nibble: coef | Flags (unused) | 28 signed nibbles (low before high): minisample snew sample = minisample <<(12-shift )+ prev[0]*coefTable[0][ coef ]+ prev[1]*coefTable[1][ coef ] |
where "coefTable" is the same as the one given in vgmstream, "prev[n]" are the (n+1)th past output samples that you must keep track of when decoding. |
0xC0 00 00 00 ...
).
It looks like Sly 2/3 associate every area to a reasonably small section of the disc, so that elements of the area can be loaded relatively quickly.
As a result, if separate indoor areas share the same music or SFX, that music track needs to be duplicated, so that it exists near the data of both areas.
Sly 3 pushed this idea to an unfeasible length:
In every area where the Guru can enter, he can transform or ride enemies (both actions are accompanied by their own music).
And in almost every area, Bentley can activate the Grapple Cam, which also has its own music.
As a result, these 3 music tracks are duplicated over and over and over and over and over and over and over again.
Respectively: 31 times (Guru Transforms), 9 times (Guru Rides), and 38 times (Grapple Cam).
The combined length of these tracks on disc, without loops, is probably longer than the time I have heard them in the game, especially "Guru Transforms".
And that's why these 3 get the special derogatory moniker of "frequent duplicates".
It looks like every file in Sly 2/3 is stored in groups of 32 sectors (treating the disc as if it were structured in "macrosectors" of 0x10000 bytes each).
When a file ends before completely filling a "macrosector", the remaining space is filled by repeating the beginning of the same file (instead of being left blank).
In some demos, that space may be filled with the beginning of a different file, so there's a slyght chance this leftover data may be of interest to passionate Sly dataminers.
Without doing any analysis myself, I'm putting up the option to download this leftover data for anyone else to use or ignore.