|
| 1 | +#### SCD FILE RESEARCH #### By Ioncannon |
| 2 | + |
| 3 | +!Some information was based on VGMStream! |
| 4 | + |
| 5 | +Current research on SCD music/sound files. Sorry it's a mess. |
| 6 | + |
| 7 | +Structure (based on 0c0000.win32.index): |
| 8 | + |
| 9 | +===SEDB SSCF HEADER=== |
| 10 | +0x00 Signature Int64; SEDBSSCF |
| 11 | +0x08 Version Int32; For FFXIV should be 3; |
| 12 | +0x0C ~~Unknown~~ Short; Seems to be always 0x0400 |
| 13 | +0x0E Header Size~~ Short; Points to the address where the next header is (also size of this header). Seems to be always 0x30. |
| 14 | +0x10 File Size Int32; Total File size |
| 15 | +~~~~~~~~Padding~~~~~~~~ Padded to fill 48 bytes (0x2F |
| 16 | + |
| 17 | +===OFFSETS HEADER=== |
| 18 | +0x00 Size of Offset Table 0 Short; |
| 19 | +0x02 Size of Sound Entry Offset Table Short; This is also the number of sounds in this file. |
| 20 | +0x04 Size of Offset Table 2 Short; |
| 21 | +0x06 ~~Unknown~~ Short; In one file: 0x0001, in another 0x270F |
| 22 | +0x08 Offset Table 0 Offset Int32; |
| 23 | +0x0C Sound Entry Offset Table Offset Int32; |
| 24 | +0x10 Offset to Offset Table 2 Int32; |
| 25 | +0x14 ~~Unknown/Null~~~ Int32; |
| 26 | +0x18 Offset To ??? Int32; |
| 27 | + |
| 28 | +--Table 0: 4 * [Size of Table 1] |
| 29 | +--Table 1: 4 * [Size of Table 2] |
| 30 | +--Table 2: 4 * [Size of Table 3] ;Offsets to Sound Entries |
| 31 | +--Table 3: 4 * [Size of Table 1] |
| 32 | + |
| 33 | +--Data 1 [Pointed from Table 3] |
| 34 | +--Data 2 [Pointed from Table 0] |
| 35 | +--Data 3 [Pointed from Table 1] |
| 36 | + 2027296 |
| 37 | +---------------MUSIC IS HERE---------------------------- |
| 38 | + |
| 39 | +===SOUND ENTRY HEADER=== (32 byte header) |
| 40 | +0x00 Music File Length Int32; |
| 41 | +0x04 Num Channels Int32; 0x01: Mono, 0x02: Stereo, FFXIV is usually 0x02 channels |
| 42 | +0x08 Frequency Int32; FFXIV is usually 44100HZ (AC440000) |
| 43 | +0x0C Data Type Int32; 0x0C: MS-ADPCM, 0x06: OGG. FFXIV seems to use OGG for music, MS-ADPCM for sound. |
| 44 | +0x10 Loop Start Int32; In Bytes. Calculation: (filesize/amount of samples)*sample |
| 45 | +0x14 Loop End Int32; Ditto, if you wanted to loop a whole song, set this to the file's size. |
| 46 | +0x18 First Frame Pos Int32; First OggS after (possibly, not always) encrypted header. |
| 47 | +0x1C Aux Chunk Count Short; Number of Aux Chunks |
| 48 | + |
| 49 | +===AUX CHUNKS=== |
| 50 | +-----MARK---- |
| 51 | +0x00 ID Int32; ASCII MARK Id |
| 52 | +0x04 Chunk Size Int32; Size of this chunk, from start to end. |
| 53 | +0x08 Mark Table ;Chunk Size / 4 entries. |
| 54 | + |
| 55 | +===IF MS-ADPCM=== |
| 56 | +WAVEFORMATEX See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd390970%28v=vs.85%29.aspx |
| 57 | +ADPCMCOEFSET Int32; * 7 |
| 58 | + |
| 59 | +===IF OGG SEEK TABLE HEADER=== (32 bytes) |
| 60 | +0x00 Encode Type Short; Seems to tell what encoding is being used. 02,20 is XOR. 03,20 is Heavensward one. |
| 61 | +0x02 Encode Byte Byte; If encoding is 02,20, XOR the header with this byte |
| 62 | +0x04 |
| 63 | +0x08 |
| 64 | +0x0c |
| 65 | +0x10 Size of Seek Table Int32; How many seek table entries there are. |
| 66 | +0x14 Vorbis Header Size Int32; Size of the Ogg Vorbis header (for decoding purpose). |
| 67 | +0x18 |
| 68 | +~~~~~~~~~Padding~~~~~~~~ Padded to fill 32bytes |
| 69 | + |
| 70 | +===SEEK TABLE=== (Size is 4 * [Num Seek Table]) |
| 71 | +0x00 Seek Entry Int32; An offset from the Vorbis header to some Ogg page. |
| 72 | + |
| 73 | +===VORBIS HEADER== (Size is [Vorbis Header Size]) |
| 74 | +-A standard Ogg Vorbis header. Check the encode byte in the seek table header to see if this header is encoded. If it is, |
| 75 | +XOR all header bytes with the encode byte. |
| 76 | +-Many songs have a LOOPSTART and LOOPEND comment tag defining where music should begin and end after the first loop. |
| 77 | + |
| 78 | +===DATA=== |
| 79 | +Ogg Vorbis data is here |
| 80 | + |
| 81 | +--------------Duplicate Header----------------------------- |
| 82 | +It seems that the first header is 3 chunks in size, each 0x120 bytes long. It's the Vorbis |
| 83 | +Indentification, Comment, and Setup headers. This is repeated after. |
| 84 | + |
| 85 | +-------------Heavensward Encoding-------------------------- |
| 86 | +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: |
| 87 | + |
| 88 | +3A 32 32 32 03 7E 12 F7 B2 E2 A2 67 32 32 22 32 |
| 89 | + |
| 90 | +The XOR table is 0xFF byte long. |
| 91 | + |
| 92 | +Example code to decode (note dataLength is [Music File Length] in the entry header): |
| 93 | + |
| 94 | +private void xorDecodeFromTable(byte[] dataFile, int dataLength) { |
| 95 | + int byte1 = dataLength & 0xFF & 0x7F; |
| 96 | + int byte2 = byte1 & 0x3F; |
| 97 | + for (int i = 0; i < dataFile.length; i++) |
| 98 | + { |
| 99 | + int xorByte = XORTABLE[(byte2 + i) & 0xFF]; |
| 100 | + xorByte &= 0xFF; |
| 101 | + xorByte ^= (dataFile[i]&0xFF); |
| 102 | + xorByte ^= byte1; |
| 103 | + dataFile[i] = (byte) xorByte; |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +--------------To Inject OGG------------------------------- |
| 108 | + |
| 109 | +-Change total file size |
| 110 | +-Change single file size |
| 111 | +-Change First Frame Position value |
| 112 | +-Change Header length value |
| 113 | +-Add data to end |
| 114 | + |
| 115 | +--------------Putting MS-ADPCM into WAV-------------------- |
| 116 | +-Write "RIFF" |
| 117 | +-Write 36 + [Size of first frame to end of file] |
| 118 | +-Write "WAVE" |
| 119 | +-Write "fmt " |
| 120 | +-Write 0x10 |
| 121 | +-Write wave header |
| 122 | +-Write "data" |
| 123 | +-Write [Size of first frame to end of file] |
| 124 | +-Write data from [Size of first frame to end of file] |
| 125 | + |
| 126 | +--------------Ogg Vorbis format info for understanding the encrypted header----------------- |
| 127 | + |
| 128 | +===OGG PAGE=== |
| 129 | +0x00 Signature Int32; Value is OggS |
| 130 | +0x04 Version Byte; Seems to be 0x00 for FFXIV |
| 131 | +0x05 Type Byte; Type of header: 0x01: Continuation, 0x02: Beginning, 0x03: End |
| 132 | +0x06 Granule Position Int64; |
| 133 | +0x0E Serial Number Int32; Seems to be 0x00 for FFXIV |
| 134 | +0x12 Sequence Number Int32; |
| 135 | +0x16 Checksum Int32; |
| 136 | +0x1E Num Page Segs Byte; Seems to be 0x01 for FFXIV |
| 137 | +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. |
| 138 | + |
| 139 | +===VORBIS PAGE=== |
| 140 | +0x00 Header Type Byte; Type of vorbis header: 0x01: ID Header, 0x03: Comment Header, 0x05: Setup Header. If has leading 0, audio header. |
| 141 | +0x01 Signature 6Bytes; VORBIS |
| 142 | + |
| 143 | +--If ID Header-- |
| 144 | +1 [vorbis_version] = read 32 bits as unsigned integer |
| 145 | +2 [audio_channels] = read 8 bit integer as unsigned |
| 146 | +3 [audio_sample_rate] = read 32 bits as unsigned integer |
| 147 | +4 [bitrate_maximum] = read 32 bits as signed integer |
| 148 | +5 [bitrate_nominal] = read 32 bits as signed integer |
| 149 | +6 [bitrate_minimum] = read 32 bits as signed integer |
| 150 | +7 [blocksize_0] = 2 exponent (read 4 bits as unsigned integer) |
| 151 | +8 [blocksize_1] = 2 exponent (read 4 bits as unsigned integer) |
| 152 | +9 [framing_flag] = read one bit |
| 153 | + |
| 154 | +--If Comment Header--- |
| 155 | +1 [vendor length] = read an unsigned integer of 32 bits |
| 156 | +2 [vendor string] = size of vendor length; Seems to be always �Xiph.Org libVorbis I 20040717� with a varying year. |
| 157 | +3 [fields] = read an unsigned integer of 32 bits; FFXIV only uses the LoopStart and LoopEnd fields |
0 commit comments