#### SCD FILE RESEARCH #### By Ioncannon !Some information was based on VGMStream! Current research on SCD music/sound files. Sorry it's a mess. Structure (based on 0c0000.win32.index): ===SEDB SSCF HEADER=== 0x00 Signature Int64; SEDBSSCF 0x08 Version Int32; For FFXIV should be 3; 0x0C ~~Unknown~~ Short; Seems to be always 0x0400 0x0E Header Size~~ Short; Points to the address where the next header is (also size of this header). Seems to be always 0x30. 0x10 File Size Int32; Total File size ~~~~~~~~Padding~~~~~~~~ Padded to fill 48 bytes (0x2F ===OFFSETS HEADER=== 0x00 Size of Offset Table 0 Short; 0x02 Size of Sound Entry Offset Table Short; This is also the number of sounds in this file. 0x04 Size of Offset Table 2 Short; 0x06 ~~Unknown~~ Short; In one file: 0x0001, in another 0x270F 0x08 Offset Table 0 Offset Int32; 0x0C Sound Entry Offset Table Offset Int32; 0x10 Offset to Offset Table 2 Int32; 0x14 ~~Unknown/Null~~~ Int32; 0x18 Offset To ??? Int32; --Table 0: 4 * [Size of Table 1] --Table 1: 4 * [Size of Table 2] --Table 2: 4 * [Size of Table 3] ;Offsets to Sound Entries --Table 3: 4 * [Size of Table 1] --Data 1 [Pointed from Table 3] --Data 2 [Pointed from Table 0] --Data 3 [Pointed from Table 1] 2027296 ---------------MUSIC IS HERE---------------------------- ===SOUND ENTRY HEADER=== (32 byte header) 0x00 Music File Length Int32; 0x04 Num Channels Int32; 0x01: Mono, 0x02: Stereo, FFXIV is usually 0x02 channels 0x08 Frequency Int32; FFXIV is usually 44100HZ (AC440000) 0x0C Data Type Int32; 0x0C: MS-ADPCM, 0x06: OGG. FFXIV seems to use OGG for music, MS-ADPCM for sound. 0x10 Loop Start Int32; In Bytes. Calculation: (filesize/amount of samples)*sample 0x14 Loop End Int32; Ditto, if you wanted to loop a whole song, set this to the file's size. 0x18 First Frame Pos Int32; First OggS after (possibly, not always) encrypted header. 0x1C Aux Chunk Count Short; Number of Aux Chunks ===AUX CHUNKS=== -----MARK---- 0x00 ID Int32; ASCII MARK Id 0x04 Chunk Size Int32; Size of this chunk, from start to end. 0x08 Mark Table ;Chunk Size / 4 entries. ===IF MS-ADPCM=== WAVEFORMATEX See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd390970%28v=vs.85%29.aspx ADPCMCOEFSET Int32; * 7 ===IF OGG SEEK TABLE HEADER=== (32 bytes) 0x00 Encode Type Short; Seems to tell what encoding is being used. 02,20 is XOR. 03,20 is Heavensward one. 0x02 Encode Byte Byte; If encoding is 02,20, XOR the header with this byte 0x04 0x08 0x0c 0x10 Size of Seek Table Int32; How many seek table entries there are. 0x14 Vorbis Header Size Int32; Size of the Ogg Vorbis header (for decoding purpose). 0x18 ~~~~~~~~~Padding~~~~~~~~ Padded to fill 32bytes ===SEEK TABLE=== (Size is 4 * [Num Seek Table]) 0x00 Seek Entry Int32; An offset from the Vorbis header to some Ogg page. ===VORBIS HEADER== (Size is [Vorbis Header Size]) -A standard Ogg Vorbis header. Check the encode byte in the seek table header to see if this header is encoded. If it is, XOR all header bytes with the encode byte. -Many songs have a LOOPSTART and LOOPEND comment tag defining where music should begin and end after the first loop. ===DATA=== Ogg Vorbis data is here --------------Duplicate Header----------------------------- It seems that the first header is 3 chunks in size, each 0x120 bytes long. It's the Vorbis Indentification, Comment, and Setup headers. This is repeated after. -------------Heavensward Encoding-------------------------- Square Enix had encrypted the Heavensward music using a strange algorithm. Before decoding, you need the XOR table which can be found in the .exe if you search for: 3A 32 32 32 03 7E 12 F7 B2 E2 A2 67 32 32 22 32 The XOR table is 0xFF byte long. Example code to decode (note dataLength is [Music File Length] in the entry header): private void xorDecodeFromTable(byte[] dataFile, int dataLength) { int byte1 = dataLength & 0xFF & 0x7F; int byte2 = byte1 & 0x3F; for (int i = 0; i < dataFile.length; i++) { int xorByte = XORTABLE[(byte2 + i) & 0xFF]; xorByte &= 0xFF; xorByte ^= (dataFile[i]&0xFF); xorByte ^= byte1; dataFile[i] = (byte) xorByte; } } --------------To Inject OGG------------------------------- -Change total file size -Change single file size -Change First Frame Position value -Change Header length value -Add data to end --------------Putting MS-ADPCM into WAV-------------------- -Write "RIFF" -Write 36 + [Size of first frame to end of file] -Write "WAVE" -Write "fmt " -Write 0x10 -Write wave header -Write "data" -Write [Size of first frame to end of file] -Write data from [Size of first frame to end of file] --------------Ogg Vorbis format info for understanding the encrypted header----------------- ===OGG PAGE=== 0x00 Signature Int32; Value is OggS 0x04 Version Byte; Seems to be 0x00 for FFXIV 0x05 Type Byte; Type of header: 0x01: Continuation, 0x02: Beginning, 0x03: End 0x06 Granule Position Int64; 0x0E Serial Number Int32; Seems to be 0x00 for FFXIV 0x12 Sequence Number Int32; 0x16 Checksum Int32; 0x1E Num Page Segs Byte; Seems to be 0x01 for FFXIV 0x1F Segment table Byte; Each segment is a byte long, * 0x1E's value. However, FFXIV's music only has 1 segment it seems, thus 1 byte size. ===VORBIS PAGE=== 0x00 Header Type Byte; Type of vorbis header: 0x01: ID Header, 0x03: Comment Header, 0x05: Setup Header. If has leading 0, audio header. 0x01 Signature 6Bytes; VORBIS --If ID Header-- 1 [vorbis_version] = read 32 bits as unsigned integer 2 [audio_channels] = read 8 bit integer as unsigned 3 [audio_sample_rate] = read 32 bits as unsigned integer 4 [bitrate_maximum] = read 32 bits as signed integer 5 [bitrate_nominal] = read 32 bits as signed integer 6 [bitrate_minimum] = read 32 bits as signed integer 7 [blocksize_0] = 2 exponent (read 4 bits as unsigned integer) 8 [blocksize_1] = 2 exponent (read 4 bits as unsigned integer) 9 [framing_flag] = read one bit --If Comment Header--- 1 [vendor length] = read an unsigned integer of 32 bits 2 [vendor string] = size of vendor length; Seems to be always “Xiph.Org libVorbis I 20040717” with a varying year. 3 [fields] = read an unsigned integer of 32 bits; FFXIV only uses the LoopStart and LoopEnd fields