|  | 
|  | 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