5,389
edits
m (fixing a newline i deleted previously) |
(note on how/where SNDDs are stored for PS2 data) |
||
Line 5: | Line 5: | ||
*On PC (both retail and demo), sounds are encoded using Microsoft's ADPCM codec (implemented in [[wp:FFmpeg|FFmpeg]] as '''adpcm_ms'''). See [https://wiki.multimedia.cx/index.php/Microsoft_ADPCM HERE] for a quick description. | *On PC (both retail and demo), sounds are encoded using Microsoft's ADPCM codec (implemented in [[wp:FFmpeg|FFmpeg]] as '''adpcm_ms'''). See [https://wiki.multimedia.cx/index.php/Microsoft_ADPCM HERE] for a quick description. | ||
*On Mac, sounds are encoded using QuickTime's IMA4 codec (implemented in FFmpeg as '''adpcm_ima_qt'''). See [https://wiki.multimedia.cx/index.php/Apple_QuickTime_IMA_ADPCM HERE] for a quick description. | *On Mac, sounds are encoded using QuickTime's IMA4 codec (implemented in FFmpeg as '''adpcm_ima_qt'''). See [https://wiki.multimedia.cx/index.php/Apple_QuickTime_IMA_ADPCM HERE] for a quick description. | ||
*On PS2, sounds are encoded using Sony's VAG codec (a.k.a. Sony PSX ADPCM, or '''adpcm_psx''' in FFmpeg). See [https://forum.devchroma.nl/index.php?topic=9.0 HERE] for a quick description. | |||
As a unique feature of Oni game data, SNDD files have a significantly different structure depending on the engine version. For PC retail (.dat/.raw storage, no .sep files), the SNDD files are larger and include a 50-byte chunk of data that is equivalent to the "fmt " chunk of a WAVE file. For the other two versions (PC demo and Mac, .dat/.raw/.sep storage), this 50-byte block is missing. It turns out that the extra format data allows the PC retail to support both MS ADPCM and IMA4, as well as uncompressed PCM, whereas PC demo and Mac engines only support MS ADPCM and IMA4, respectively. (It has not been confirmed whether the PC retail engine supports other WAVE formats beyond PCM and MS ADPCM, such as Mu-Law or A-Law PCM, IEEE float PCM, etc.) The PS2 engine uses the same short data header as for PC demo and Mac, but the waveform is stored as VAG (a.k.a. PSX ADPCM) and resides in a completely separate SOUNDS folder, accessed through an additional layer of indexation beyond the usual .dat/.raw./.sep logic (not unlike PS2 TXMPs which rely on color palettes stored in additional level#_palette.pal files). | |||
---- | ---- | ||
For clarity, the simpler and more straightforward SNDDs of PC demo and Mac are documented first, followed by the more complex and versatile PC retail SNDDs. | For clarity, the simpler and more straightforward SNDDs of PC demo and Mac are documented first, followed by the more complex and versatile PC retail SNDDs. | ||
:(Historically, though, the PC retail implementation is older, and the PC demo and Mac versions were trimmed-down iterations of PC retail.) | :(Historically, though, the PC retail implementation is older, and the PC demo and Mac versions were trimmed-down iterations of PC retail.) | ||
The exotic PS2 storage is documented last, after which we list some legacy tips (for manual sound conversion) and known issues/limitations, as well as the current sound capabilities of OniX and OniSplit. | |||
==Mac and PC demo== | ==Mac and PC demo== | ||
Line 360: | Line 364: | ||
;Effect of "1" and "2" flags | ;Effect of "1" and "2" flags | ||
:It is possible that the "1" and "2" flags used to affect playback in raw PCM mode (something about swapping the .raw data to allow both for Little Endian and Big Endian PCM samples), but currently they do not seem to have any effect. | :It is possible that the "1" and "2" flags used to affect playback in raw PCM mode (something about swapping the .raw data to allow both for Little Endian and Big Endian PCM samples), but currently they do not seem to have any effect. | ||
==PS2 implementation== | |||
The PS2 implementation has an unorthodox approach to raw data when it comes to SNDDs. Here are the .dat parts of the SNDDs in a PS2 level0_Final.dat file. | |||
{|cellpadding=3 cellspacing=0 style="line-height:13px" | |||
{{HexRow|0xD5EA0| | |||
|01|5B|0E|00|01|00|00|00|00|00|00|00|9E|01|00|00| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|00|00|00|00|FF|FF|FF|FF|C8|C8|C8|C8|FF|FF|FF|FF| | |||
|00|00|00|00|00|00|00|00|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5EB0| | |||
|20|F7|00|00|40|30|76|13|AD|DE|AD|DE|AD|DE|AD|DE| | |||
|C8|C8|C8|C8|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5EC0| | |||
|01|5C|0E|00|01|00|00|00|00|00|00|00|9E|01|01|00| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|00|00|00|00|FF|FF|FF|FF|C8|C8|C8|C8|FF|FF|FF|FF| | |||
|00|00|00|00|00|00|00|00|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5ED0| | |||
|A0|F6|00|00|C0|37|77|13|AD|DE|AD|DE|AD|DE|AD|DE| | |||
|C8|C8|C8|C8|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5EE0| | |||
|01|5D|0E|00|01|00|00|00|00|00|00|00|8F|02|02|00| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|00|00|00|00|FF|FF|FF|FF|C8|C8|C8|C8|FF|FF|FF|FF| | |||
|00|00|00|00|00|00|00|00|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5EF0| | |||
|40|86|01|00|C0|2E|78|13|AD|DE|AD|DE|AD|DE|AD|DE| | |||
|C8|C8|C8|C8|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5F00| | |||
|01|5E|0E|00|01|00|00|00|00|00|00|00|91|02|03|00| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|00|00|00|00|FF|FF|FF|FF|C8|C8|C8|C8|FF|FF|FF|FF| | |||
|00|00|00|00|00|00|00|00|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5F10| | |||
|40|87|01|00|40|B5|79|13|AD|DE|AD|DE|AD|DE|AD|DE| | |||
|C8|C8|C8|C8|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5F20| | |||
|01|5F|0E|00|01|00|00|00|00|00|00|00|3C|01|04|00| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|00|00|00|00|FF|FF|FF|FF|C8|C8|C8|C8|FF|FF|FF|FF| | |||
|00|00|00|00|00|00|00|00|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
{{HexRow|0xD5F30| | |||
|60|BC|00|00|00|0A|75|13|AD|DE|AD|DE|AD|DE|AD|DE| | |||
|C8|C8|C8|C8|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|FF|FF|FF|FF|FF|FF|FF|FF|C8|C8|C8|C8|C8|C8|C8|C8| | |||
|C8|C8|C8|C8|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF|FF| | |||
|°°°°°°°°°°°°°°°° | |||
}} | |||
|} | |||
(Yes, the PS2 retail level0_Final.dat only has those five sounds. All the other sounds (weapons, particles, impacts, footsteps, etc) are stored per-chapter, which causes a lot of duplicates but supposedly lightens the memory usage for a given level.) | |||
As you can see, so far this is quite similar to the PC demo and Mac SNDDs described above (and the SNDD template checksum is indeed the same for PC demo, Mac and PS2, implying that the data structure in the .dat is the same). | |||
However, there are major novelties/anomalies (apart from the all the music being mono). First, the five .raw offsets at the end of each SNDD are obviously not pointers into level0_Final.raw or level0_Final.sep (the .raw's size is 4 MB, the .sep's 6MB, and the pointers are in the 311 MB range, possibly pointing into a memory region where the sounds will be stored at runtime). Second, the 2-byte padding field between the duration and the .raw storage size is obviously not blank here; rather, it is an index into a file called SOUNDS\LEVEL0\SOUND.DAT, which looks like this: | |||
0x00: '''''00 00 20 F7 00 00 00 00 00 00''''' 01 00 A0 F6 00 00 | |||
0x10: 20 F7 00 00 '''''02 00 40 86 01 00 C0 ED 01 00''''' 03 00 | |||
0x20: 40 87 01 00 00 74 03 00 '''''04 00 60 BC 00 00 40 FB''''' | |||
0x30: '''''04 00''''' FE FF | |||
These are 5 blocks of 10 bytes each. For each sound there is a 2-byte index, then a 4-byte data size (including padding), then the offset at which the data is stored in the SOUNDS\LEVEL0\SOUND.SEP file. The .SEP data for each sound consists of 32 blank bytes followed by a large number of VAG packets (16 bytes each), the final VAG packet having a terminating bit set. At the very end of the .SEP file is a terminating pair of bytes, FE FF, same as in the .DAT file. The file SOUNDS\LEVEL0\SOUND.RAW exists in the same folder, but has no data except for the two bytes FE FF. | |||
For all the levels other than LEVEL0 (i.e., game chapters), the file SOUNDS\LEVEL#\SOUND.RAW is about 1 MB in size and has some non-trivial sound data. (Looks like an assembly of complete VAG sounds, with headers.) However, this data doesn't seem to be referenced from SOUNDS\LEVEL#\SOUND.DAT, which only points to the much larger SOUNDS\LEVEL#\SOUND.SEP (thus the purpose of SOUNDS\LEVEL#\SOUND.RAW is currently not clear). | |||