public void parseSTREAMMetadata(string[] STREAMMetadata) { STREAM_ID = convertStringtoInt(getSpecificFileInfoProperties("STREAM ID: ", STREAMMetadata)); audioEntries = convertStringtoInt(getSpecificFileInfoProperties("Number of audio files: ", STREAMMetadata)); for (int i = 0; i < audioEntries; i++) { STREAMFileInfo streamFileInfo = new STREAMFileInfo(); string from = "#Sound: " + (i + 1).ToString(); string end = "#Sound: " + (i + 2).ToString(); // Getting individual Info for each files string[] STREAMSoundInfo = getSpecificFileInfoPropertiesRegion(STREAMMetadata, from, end); uint codec = convertStringtoUInt(getSpecificFileInfoProperties("Codec: ", STREAMSoundInfo)); uint loop_start = convertStringtoUInt(getSpecificFileInfoProperties("Loop Start: ", STREAMSoundInfo)); uint loop_length = convertStringtoUInt(getSpecificFileInfoProperties("Loop Length: ", STREAMSoundInfo)); uint loop_flag = convertStringtoUInt(getSpecificFileInfoProperties("Loop Flag: ", STREAMSoundInfo)); float loop_float = convertStringtoFloat(getSpecificFileInfoProperties("Loop Float: ", STREAMSoundInfo)); float loop_float_2 = convertStringtoFloat(getSpecificFileInfoProperties("Loop Float 2: ", STREAMSoundInfo)); uint var_0x50 = convertStringtoUInt(getSpecificFileInfoProperties("var_0x50: ", STREAMSoundInfo)); uint var_0x54 = convertStringtoUInt(getSpecificFileInfoProperties("var_0x54: ", STREAMSoundInfo)); uint var_0x60 = convertStringtoUInt(getSpecificFileInfoProperties("var_0x60: ", STREAMSoundInfo)); float var_0x6C = convertStringtoFloat(getSpecificFileInfoProperties("var_0x6C: ", STREAMSoundInfo)); uint var_0x70 = convertStringtoUInt(getSpecificFileInfoProperties("var_0x70: ", STREAMSoundInfo)); uint var_0x9C = convertStringtoUInt(getSpecificFileInfoProperties("var_0x9C: ", STREAMSoundInfo)); uint var_0xAC = convertStringtoUInt(getSpecificFileInfoProperties("var_0xAC: ", STREAMSoundInfo)); string file_Name = getSpecificFileInfoProperties("fileName: ", STREAMSoundInfo); streamFileInfo.codec = codec; streamFileInfo.loop_start = loop_start; streamFileInfo.loop_length = loop_length; streamFileInfo.loop_flag = loop_flag; streamFileInfo.loop_float = loop_float; streamFileInfo.loop_float_2 = loop_float_2; streamFileInfo.var_0x50 = var_0x50; streamFileInfo.var_0x54 = var_0x54; streamFileInfo.var_0x60 = var_0x60; streamFileInfo.var_0x6C = var_0x6C; streamFileInfo.var_0x70 = var_0x70; streamFileInfo.var_0x9C = var_0x9C; streamFileInfo.var_0xAC = var_0xAC; streamFileInfo.file_Name = file_Name; streamFileInfoList.Add(streamFileInfo); } }
public MemoryStream repackAudioFiles() { MemoryStream STREAM = new MemoryStream(); MemoryStream STREAMHeader = new MemoryStream(); MemoryStream STREAMData = new MemoryStream(); MemoryStream STREAMGeneralInfo = new MemoryStream(); MemoryStream STREAMAudioInfo = new MemoryStream(); List <uint> STREAMInfoPointers = new List <uint>(); // Calculate the first pointer. // Stream general info header is 0x20 in length, and each info file occupies 4 byte pointer, alongside padding. uint first_Pointer = (uint)addPaddingSizeCalculation(0x20 + (soundFiles.Count * 0x4)); STREAMInfoPointers.Add(first_Pointer); for (int i = 0; i < soundFiles.Count; i++) { STREAMFileInfo fileInfo = streamFileInfoList[i]; // check the info's codec, we target the repack conversion to this. uint codec = fileInfo.codec; supportedAudioCodec targetCodec = determineInfoCodec(codec); FileInfo file = soundFiles[i]; FileStream fs = file.OpenRead(); MemoryStream ms = new MemoryStream(); fs.CopyTo(ms); ms.Seek(0, SeekOrigin.Begin); fileName = Path.GetFileName(file.FullName); supportedAudioCodec currentCodec = supportedAudioCodec.NONE; MemoryStream baseFormatStream = new MemoryStream(); // Converting the input file to pcm if the file is not the same as the targetCodec uint magic = readUIntBigEndian(ms); switch (magic) { case 0x52494646: // RIFF (pcm, at3) // Need to call this to set the correct currentCodec (differentiate between pcm and at3) currentCodec = determineRIFFCodec(ms); convertToBaseFormat(file, currentCodec, targetCodec).CopyTo(baseFormatStream); break; case 0x424E5346: // BNSF (is14) currentCodec = supportedAudioCodec.BNSF; convertToBaseFormat(file, currentCodec, targetCodec).CopyTo(baseFormatStream); break; case 0x56414770: // VAGp (vag) currentCodec = supportedAudioCodec.VAG; convertToBaseFormat(file, currentCodec, targetCodec).CopyTo(baseFormatStream); break; default: break; } // format ms to be appended on STREAM header. MemoryStream sub_header_MS; // the actual stream audio data to be appended. MemoryStream stream_data_MS; baseFormatStream.Seek(0, SeekOrigin.Begin); uint baseFmtMagic = readUIntBigEndian(baseFormatStream); switch (targetCodec) { case supportedAudioCodec.AT3: if (baseFmtMagic == 0x52494646 && determineRIFFCodec(baseFormatStream) == supportedAudioCodec.PCM) { baseFormatStream = new MemoryStream(convertWAVtoAT3(file.FullName)); } parseAT3(baseFormatStream, out sub_header_MS, out stream_data_MS); break; case supportedAudioCodec.BNSF: if (baseFmtMagic == 0x52494646) { // the only way to know sample size (duration) of the audio file is to calculate through the unencoded RIFF file. uint sample_size = determinePCMSampleSize(baseFormatStream); baseFormatStream = new MemoryStream(convertPCMtoBNSF(file.FullName, 48000, 14000, sample_size)); } parseBNSF(baseFormatStream, out sub_header_MS, out stream_data_MS); break; case supportedAudioCodec.VAG: if (baseFmtMagic == 0x52494646) { baseFormatStream = new MemoryStream(convertPCMtoVAG(file.FullName)); } parseVAG(baseFormatStream, out sub_header_MS, out stream_data_MS); break; default: throw new Exception("Codec not yet supported for file: " + fileName); } // Start writing STREAM Header MemoryStream audio_Info = new MemoryStream(); // write codec magic switch (targetCodec) { case supportedAudioCodec.AT3: appendUIntMemoryStream(audio_Info, 0x61743300, true); break; case supportedAudioCodec.BNSF: appendUIntMemoryStream(audio_Info, 0x69733134, true); break; case supportedAudioCodec.VAG: appendUIntMemoryStream(audio_Info, 0x76616700, true); break; default: throw new Exception("Codec not yet supported for file: " + fileName); } // general infos appendIntMemoryStream(audio_Info, STREAM_ID, true); // STREAM_ID appendUIntMemoryStream(audio_Info, (uint)i, true); // file index appendUIntMemoryStream(audio_Info, fileInfo.codec, true); // codec enum appendUIntMemoryStream(audio_Info, 0, true); // unk_0x10, always 0 // size and offsets appendUIntMemoryStream(audio_Info, (uint)stream_data_MS.Length, true); // size of stream data appendUIntMemoryStream(audio_Info, (uint)STREAMData.Length, true); // relative offset of the stream data from the top appendUIntMemoryStream(audio_Info, (uint)sub_header_MS.Length, true); // subheader size // Loop stuff appendUIntMemoryStream(audio_Info, fileInfo.loop_start, true); appendUIntMemoryStream(audio_Info, fileInfo.loop_length, true); appendUIntMemoryStream(audio_Info, fileInfo.loop_flag, true); appendUIntMemoryStream(audio_Info, 0, true); // always 0 // unknown section appendUIntMemoryStream(audio_Info, 0xFFFFFFFF, true); // unk_0x30, always 0xFFFFFFFF appendFloatMemoryStream(audio_Info, fileInfo.loop_float, true); // loop_float, if there's no loop this is populated. appendFloatMemoryStream(audio_Info, fileInfo.loop_float_2, true); // -99 float (0xC2C60000) without loop appendUIntMemoryStream(audio_Info, 0, true); // unk_0x3C, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x40, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x44, always 0 appendFloatMemoryStream(audio_Info, 1, true); // unk_0x48, always 1 float (0x3F800000) appendUIntMemoryStream(audio_Info, 0, true); // unk_0x4C, always 0 appendFloatMemoryStream(audio_Info, fileInfo.var_0x50, true); // at3 / is14 = 1(Float), vag / wav = 0 appendUIntMemoryStream(audio_Info, fileInfo.var_0x54, true); // at3/is14 = 0xA, vag = 0x4, wav = 0 appendFloatMemoryStream(audio_Info, 1, true); // unk_0x58, always 1 float (0x3F800000) appendFloatMemoryStream(audio_Info, 1, true); // unk_0x5C, always 1 float (0x3F800000) appendUIntMemoryStream(audio_Info, fileInfo.var_0x60, true); // different for each header, not sure what. appendUIntMemoryStream(audio_Info, 0, true); // unk_0x64, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x68, always 0 appendFloatMemoryStream(audio_Info, fileInfo.var_0x6C, true); // vag = 0, others = -100 appendUIntMemoryStream(audio_Info, fileInfo.var_0x70, true); // different for each header, not sure what. appendUIntMemoryStream(audio_Info, 0x64, true); // unk_0x74, always 0x64 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x78, always 0 appendUIntMemoryStream(audio_Info, 1, true); // unk_0x7C, always 1 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x80, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x84, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x88, always 0 appendFloatMemoryStream(audio_Info, 1, true); // unk_0x8C, always 1 appendUIntMemoryStream(audio_Info, 0x14, true); // unk_0x90, always 0x14 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x94, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0x98, always 0 appendUIntMemoryStream(audio_Info, fileInfo.var_0x9C, true); appendUIntMemoryStream(audio_Info, 0, true); // unk_0xA0, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0xA4, always 0 appendFloatMemoryStream(audio_Info, 1, true); // unk_0xA8, always 1 appendUIntMemoryStream(audio_Info, fileInfo.var_0xAC, true); // vag = 1, others = 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0xB0, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0xB4, always 0 appendUIntMemoryStream(audio_Info, 0, true); // unk_0xB8, always 0 sub_header_MS.Seek(0, SeekOrigin.Begin); sub_header_MS.CopyTo(audio_Info); addPaddingStream(audio_Info); uint nextPointer = STREAMInfoPointers.Last() + (uint)audio_Info.Length; STREAMInfoPointers.Add(nextPointer); MemoryStream stream_data_MS_appended = new MemoryStream(); stream_data_MS.Seek(0, SeekOrigin.Begin); stream_data_MS.CopyTo(stream_data_MS_appended); addPaddingStream(stream_data_MS_appended); audio_Info.Seek(0, SeekOrigin.Begin); stream_data_MS_appended.Seek(0, SeekOrigin.Begin); audio_Info.CopyTo(STREAMAudioInfo); stream_data_MS_appended.CopyTo(STREAMData); } addPaddingStream(STREAMData); // Formula to know how many zero to append at the end of STREAM Header. // STREAM Header is stored in 2kb size sections. Hence, the size of the STREAM header must be divisible by 2048. // Hence, we get the last pointer to the audio Info, use modulo to find the remains, subtract the pointer with it to get the lower 2048 factor // After that we add the number with 2048 uint lastPointer = STREAMInfoPointers.Last(); uint STREAMHeaderSize = (lastPointer - (lastPointer % 2048)) + 2048; uint appendSize = STREAMHeaderSize - lastPointer; appendUIntMemoryStream(STREAMGeneralInfo, 0x00020100, true); // STREAM Version, also functions as magic appendUIntMemoryStream(STREAMGeneralInfo, 0, true); // Should be 0 for all cases appendIntMemoryStream(STREAMGeneralInfo, STREAM_ID, true); appendUIntMemoryStream(STREAMGeneralInfo, (uint)soundFiles.Count, true); appendUIntMemoryStream(STREAMGeneralInfo, STREAMHeaderSize, true); appendUIntMemoryStream(STREAMGeneralInfo, (uint)STREAMData.Length, true); appendUIntMemoryStream(STREAMGeneralInfo, 0x20, true); // The size of general Info, should be 0x20 for all cases. appendUIntMemoryStream(STREAMGeneralInfo, STREAMInfoPointers.First(), true); // The starting point of the audio Info, or the first pointer for (int k = 0; k < STREAMInfoPointers.Count; k++) { uint pointer = STREAMInfoPointers[k]; if (k != STREAMInfoPointers.Count - 1) { appendUIntMemoryStream(STREAMGeneralInfo, pointer, true); } } addPaddingStream(STREAMGeneralInfo); STREAMGeneralInfo.Seek(0, SeekOrigin.Begin); STREAMAudioInfo.Seek(0, SeekOrigin.Begin); STREAMGeneralInfo.CopyTo(STREAMHeader); STREAMAudioInfo.CopyTo(STREAMHeader); appendZeroMemoryStream(STREAMHeader, (int)appendSize); STREAMHeader.Seek(0, SeekOrigin.Begin); STREAMData.Seek(0, SeekOrigin.Begin); STREAMHeader.CopyTo(STREAM); STREAMData.CopyTo(STREAM); return(STREAM); }