예제 #1
0
        private void WriteDataBlock(DataBlock block, SegmentPointer location, IStream stream, ITag tag = null)
        {
            if (tag == null && _dataBlockAddresses.ContainsKey(block))             // Don't write anything if the block has already been written
            {
                return;
            }

            // Associate the location with the block
            _dataBlockAddresses[block] = location.AsPointer();

            // Create a MemoryStream and write the block data to it (so fixups can be performed before writing it to the file)
            using (var buffer = new MemoryStream(block.Data.Length))
            {
                var bufferWriter = new EndianWriter(buffer, stream.Endianness);
                bufferWriter.WriteBlock(block.Data);

                // Apply fixups
                FixBlockReferences(block, bufferWriter, stream);
                FixTagReferences(block, bufferWriter, stream);
                FixResourceReferences(block, bufferWriter, stream);
                FixStringIdReferences(block, bufferWriter);
                if (tag != null)
                {
                    FixUnicListReferences(block, tag, bufferWriter, stream);
                }
                FixModelDataReferences(block, bufferWriter, stream, location);
                FixEffectReferences(block, bufferWriter);

                // sort after fixups
                if (block.Sortable && block.EntrySize >= 4)
                {
                    var entries      = new List <Tuple <uint, byte[]> >();
                    var bufferReader = new EndianReader(buffer, stream.Endianness);

                    for (int i = 0; i < block.EntryCount; i++)
                    {
                        buffer.Position = i * block.EntrySize;
                        uint   sid  = bufferReader.ReadUInt32();
                        byte[] rest = bufferReader.ReadBlock(block.EntrySize - 4);
                        entries.Add(new Tuple <uint, byte[]>(sid, rest));
                    }
                    buffer.Position = 0;
                    foreach (var entry in entries.OrderBy(e => e.Item1))
                    {
                        bufferWriter.WriteUInt32(entry.Item1);
                        bufferWriter.WriteBlock(entry.Item2);
                    }
                }

                // Write the buffer to the file
                stream.SeekTo(location.AsOffset());
                stream.WriteBlock(buffer.ToArray(), 0, (int)buffer.Length);
            }

            // Write shader fixups (they can't be done in-memory because they require cache file expansion)
            FixShaderReferences(block, stream, location);
        }
예제 #2
0
        private void WriteDataBlock(DataBlock block, SegmentPointer location, IStream stream)
        {
            // Don't write anything if the block has already been written
            if (_dataBlockAddresses.ContainsKey(block))
            {
                return;
            }

            // Associate the location with the block
            _dataBlockAddresses[block] = location.AsPointer();

            // Create a MemoryStream and write the block data to it (so fixups can be performed before writing it to the file)
            using (var buffer = new MemoryStream(block.Data.Length))
            {
                var bufferWriter = new EndianWriter(buffer, stream.Endianness);
                bufferWriter.WriteBlock(block.Data);

                // Apply fixups
                FixBlockReferences(block, bufferWriter, stream);
                FixTagReferences(block, bufferWriter, stream);
                FixResourceReferences(block, bufferWriter, stream);
                FixStringIDReferences(block, bufferWriter);

                // Write the buffer to the file
                stream.SeekTo(location.AsOffset());
                stream.WriteBlock(buffer.GetBuffer(), 0, (int)buffer.Length);
            }

            // Write shader fixups (they can't be done in-memory because they require cache file expansion)
            FixShaderReferences(block, stream, (int)location.AsOffset());
        }
예제 #3
0
        /// <summary>
        /// Reads a shader from a stream and then serializes it into a byte array which can then be exported.
        /// </summary>
        /// <param name="reader">The stream to read from. It should be positioned at the beginning of the shader pointer.</param>
        /// <param name="type">The type of shader to read.</param>
        /// <returns>
        /// The serialized shader data, or <c>null</c> if reading failed.
        /// </returns>
        public byte[] ExportShader(IReader reader, ShaderType type)
        {
            var info = ReadShaderInfo(reader, type);

            if (info == null)
            {
                return(null);
            }

            using (var memStream = new MemoryStream())
            {
                using (var writer = new EndianWriter(memStream, Endian.BigEndian))
                {
                    writer.WriteInt32(SerializationMagic);
                    writer.WriteByte((byte)type);

                    // Write the layout size for compatibility checking when deserializing
                    if (type == ShaderType.Pixel)
                    {
                        writer.WriteInt32(_pixelShaderInfoLayout.Size);
                    }
                    else
                    {
                        writer.WriteInt32(_vertexShaderInfoLayout.Size);
                    }

                    // Write the raw debug info
                    reader.SeekTo(info.DebugInfoOffset);
                    writer.WriteUInt32(info.DebugInfoSize);
                    writer.WriteBlock(reader.ReadBlock((int)info.DebugInfoSize));

                    // Write the raw shader data
                    var dataOffset = _cacheFile.MetaArea.PointerToOffset(info.DataAddress);
                    reader.SeekTo(dataOffset);
                    writer.WriteUInt32(info.DataSize);
                    writer.WriteBlock(reader.ReadBlock((int)info.DataSize));

                    // Create the result from the memory stream's buffer
                    var result = new byte[memStream.Length];
                    Buffer.BlockCopy(memStream.ToArray(), 0, result, 0, (int)memStream.Length);
                    return(result);
                }
            }
        }
예제 #4
0
        public static void Copy(EndianReader input, EndianWriter output, int size)
        {
            const int BufferSize = 0x1000;

            byte[] buffer = new byte[BufferSize];
            while (size > 0)
            {
                int read = input.ReadBlock(buffer, 0, Math.Min(BufferSize, size));
                output.WriteBlock(buffer, 0, read);
                size -= BufferSize;
            }
        }
예제 #5
0
        public static void Copy(EndianReader input, EndianWriter output)
        {
            // http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances-c-sharp
            const int BufferSize = 0x1000;

            byte[] buffer = new byte[BufferSize];
            int    read;

            while ((read = input.ReadBlock(buffer, 0, BufferSize)) > 0)
            {
                output.WriteBlock(buffer, 0, read);
            }
        }
예제 #6
0
        public override void Serialize(Stream stream)
        {
            using (var writer = new EndianWriter(stream, Endian.BigEndian))
            {
                var buildNameBytes = System.Text.Encoding.UTF8.GetBytes(BuildName);
                writer.WriteInt32(buildNameBytes.Length);
                writer.WriteBlock(buildNameBytes);

                var cacheNameBytes = System.Text.Encoding.UTF8.GetBytes(CacheName);
                writer.WriteInt32(cacheNameBytes.Length);
                writer.WriteBlock(cacheNameBytes);

                var count = Actions.Count;
                writer.WriteInt32(count);

                foreach (var action in Actions)
                {
                    writer.WriteInt64(action.Position);
                    writer.WriteInt32(action.Buffer.Length);
                    writer.WriteBlock(action.Buffer);
                }
            }
        }
예제 #7
0
        public void ExtractWAV(CacheFile.IndexItem blamTag, string directory)
        {
            Console.WriteLine($"Extracting {blamTag.Name}.sound");
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            var blamContext = new CacheSerializationContext(ref BlamCache, blamTag);

            var sound = BlamCache.Deserializer.Deserialize <Sound>(blamContext);

            var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount);

            var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize);

            if (xmaData == null)
            {
                Console.WriteLine($"ERROR: Failed to find sound data!");
                return;
            }

            var    OutDir     = directory;
            string sound_name = blamTag.Name.Replace('\\', '_');

            sound_name = Path.Combine(directory, sound_name);

            for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++)
            {
                var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;
                var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);

                for (int i = 0; i < permutationCount; i++)
                {
                    string permutationName = $"{sound_name}_{relativePitchRangeIndex}_{i}";
                    permutationName += ".mp3";

                    BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData);
                    using (EndianWriter output = new EndianWriter(new FileStream(permutationName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                    {
                        output.WriteBlock(blamSound.Data);
                    }
                }
            }
        }
예제 #8
0
 /// <summary>
 /// Write a DDS header
 /// </summary>
 /// <param name="writer"></param>
 public override void Write(EndianWriter writer)
 {
     writer.Format = EndianFormat.LittleEndian;
     writer.Write((uint)0x20534444);   // DDS
     writer.Write(Size);
     writer.Write((int)Flags);
     writer.Write(Height);
     writer.Write(Width);
     writer.Write(PitchOrLinearSize);
     writer.Write(Depth);
     writer.Write(MipMapCount);
     writer.WriteBlock(Reserved1);
     PixelFormat.Write(writer);
     writer.Write((int)Caps);
     writer.Write((int)Caps2);
     writer.Write(Caps3);
     writer.Write(Caps4);
     writer.Write(Reserved2);
 }
예제 #9
0
 override public void WriteChunk(EndianWriter writer)
 {
     writer.Format = EndianFormat.LittleEndian;
     writer.Write(Length);
     writer.WriteBlock(FileName);
     writer.Write(SampleCount);
     writer.Write(CompressedFileLength);
     writer.Write(LoopBegin);
     writer.Write(LoopEnd);
     writer.Write(Mode);
     writer.Write(SampleRate);
     writer.Write(Volume);
     writer.Write(Pan);
     writer.Write(Pri);
     writer.Write(ChannelCount);
     writer.Write(MinDistance);
     writer.Write(MaxDistance);
     writer.Write(VariableFrequency);
     writer.Write(VariableVolume);
     writer.Write(VariablePan);
 }
예제 #10
0
        private byte[] ConvertGen3SoundData(GameCache cache, Sound definition, byte[] soundData)
        {
            // todo: use PortingContextFactory here (currently inaccessible)
            SoundCacheFileGestalt blamSoundGestalt = null;

            foreach (var tag in cache.TagCache.TagTable)
            {
                if (tag.Group.Tag == "ugh!")
                {
                    using (var stream = cache.OpenCacheRead())
                        blamSoundGestalt = cache.Deserialize <SoundCacheFileGestalt>(stream, tag);
                    break;
                }
            }

            // ExportSoundCommand code
            using (MemoryStream soundDataStream = new MemoryStream())
            {
                using (EndianWriter output = new EndianWriter(soundDataStream, EndianFormat.BigEndian))
                {
                    if (blamSoundGestalt != null)
                    {
                        for (int pitchRangeIndex = definition.SoundReference.PitchRangeIndex; pitchRangeIndex < definition.SoundReference.PitchRangeIndex + definition.SoundReference.PitchRangeCount; pitchRangeIndex++)
                        {
                            var relativePitchRangeIndex = pitchRangeIndex - definition.SoundReference.PitchRangeIndex;
                            var permutationCount        = blamSoundGestalt.GetPermutationCount(pitchRangeIndex);

                            for (int i = 0; i < permutationCount; i++)
                            {
                                BlamSound blamSound = SoundConverter.ConvertGen3Sound(cache, blamSoundGestalt, definition, relativePitchRangeIndex, i, soundData);

                                output.WriteBlock(blamSound.Data);
                            }
                        }
                    }
                }

                return(soundDataStream.ToArray());
            }
        }
예제 #11
0
        private Sound ConvertSound(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, Sound sound, string blamTag_Name)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            if (!File.Exists(@"Tools\ffmpeg.exe") || !File.Exists(@"Tools\towav.exe"))
            {
                Console.WriteLine("Failed to locate sound conversion tools, please install ffmpeg and towav in the Tools folder");
                return(null);
            }

            //
            // Convert Sound Tag Data
            //

            var platformCodec      = BlamSoundGestalt.PlatformCodecs[sound.SoundReference.PlatformCodecIndex];
            var playbackParameters = BlamSoundGestalt.PlaybackParameters[sound.SoundReference.PlaybackParameterIndex];
            var scale          = BlamSoundGestalt.Scales[sound.SoundReference.ScaleIndex];
            var promotion      = sound.SoundReference.PromotionIndex != -1 ? BlamSoundGestalt.Promotions[sound.SoundReference.PromotionIndex] : new Promotion();
            var customPlayBack = sound.SoundReference.CustomPlaybackIndex != -1 ? new List <CustomPlayback> {
                BlamSoundGestalt.CustomPlaybacks[sound.SoundReference.CustomPlaybackIndex]
            } : new List <CustomPlayback>();
            var loop = sound.Flags.HasFlag(Sound.FlagsValue.LoopingSound);

            sound.PlaybackParameters = playbackParameters;
            sound.Scale           = scale;
            sound.PlatformCodec   = platformCodec.DeepClone();
            sound.Promotion       = promotion;
            sound.CustomPlayBacks = customPlayBack;

            //
            // Tag fixes
            //

            sound.SampleRate = platformCodec.SampleRate;
            sound.ImportType = ImportType.SingleLayer;
            // helps looping sound? there is another value, 10 for Unknown2 but I don't know when to activate it.
            if (sound.SoundReference.PitchRangeCount > 1)
            {
                sound.ImportType = ImportType.MultiLayer;
            }

            sound.PlatformCodec.LoadMode = 0;

            //
            // Process all the pitch ranges
            //

            var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount);

            if (xmaFileSize < 0)
            {
                return(null);
            }

            var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize);

            if (xmaData == null)
            {
                return(null);
            }

            sound.PitchRanges = new List <PitchRange>(sound.SoundReference.PitchRangeCount);

            var soundDataAggregate     = new byte[0].AsEnumerable();
            var currentSoundDataOffset = 0;
            var totalSampleCount       = (uint)0;

            for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++)
            {
                totalSampleCount += BlamSoundGestalt.GetSamplesPerPitchRange(pitchRangeIndex);

                //
                // Convert Blam pitch range to ElDorado format
                //

                var pitchRange = BlamSoundGestalt.PitchRanges[pitchRangeIndex];
                pitchRange.ImportName           = ConvertStringId(BlamSoundGestalt.ImportNames[pitchRange.ImportNameIndex].Name);
                pitchRange.PitchRangeParameters = BlamSoundGestalt.PitchRangeParameters[pitchRange.PitchRangeParametersIndex];
                pitchRange.Unknown1             = 0;
                pitchRange.Unknown2             = 0;
                pitchRange.Unknown3             = 0;
                pitchRange.Unknown4             = 0;
                pitchRange.Unknown5             = -1;
                pitchRange.Unknown6             = -1;
                //I suspect this unknown7 to be a flag to tell if there is a Unknownblock in extrainfo. (See a sound in udlg for example)
                pitchRange.Unknown7         = 0;
                pitchRange.PermutationCount = (byte)BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);
                pitchRange.Unknown8         = -1;

                // Add pitch range to ED sound
                sound.PitchRanges.Add(pitchRange);
                var newPitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;
                sound.PitchRanges[newPitchRangeIndex].Permutations = new List <Permutation>();

                //
                // Determine the audio channel count
                //

                var channelCount = Encoding.GetChannelCount(sound.PlatformCodec.Encoding);

                //
                // Set compression format
                //

                sound.PlatformCodec.Compression = Compression.MP3;

                //
                // Convert Blam permutations to ElDorado format
                //

                var useCache = Sounds.UseAudioCacheCommand.AudioCacheDirectory != null;

                var basePermutationCacheName = Path.Combine(
                    useCache ? Sounds.UseAudioCacheCommand.AudioCacheDirectory.FullName : TempDirectory.FullName,
                    GetTagFileFriendlyName(blamTag_Name));

                var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);
                var permutationOrder        = BlamSoundGestalt.GetPermutationOrder(pitchRangeIndex);
                var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;

                for (int i = 0; i < permutationCount; i++)
                {
                    var permutationIndex  = pitchRange.FirstPermutationIndex + i;
                    var permutationSize   = BlamSoundGestalt.GetPermutationSize(permutationIndex);
                    var permutationOffset = BlamSoundGestalt.GetPermutationOffset(permutationIndex);

                    var permutation = BlamSoundGestalt.GetPermutation(permutationIndex).DeepClone();

                    permutation.ImportName            = ConvertStringId(BlamSoundGestalt.ImportNames[permutation.ImportNameIndex].Name);
                    permutation.SkipFraction          = new Bounds <float>(0.0f, permutation.Gain);
                    permutation.PermutationChunks     = new List <PermutationChunk>();
                    permutation.PermutationNumber     = (uint)permutationOrder[i];
                    permutation.IsNotFirstPermutation = (uint)(permutation.PermutationNumber == 0 ? 0 : 1);

                    string permutationName = $"{basePermutationCacheName}_{relativePitchRangeIndex}_{i}";

                    string extension = "mp3";

                    var cacheFileName = $"{permutationName}.{extension}";

                    bool exists = File.Exists(cacheFileName);

                    byte[] permutationData = null;

                    if (!exists || !useCache)
                    {
                        BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData);
                        permutationData = blamSound.Data;
                        if (useCache)
                        {
                            using (EndianWriter output = new EndianWriter(new FileStream(cacheFileName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                            {
                                output.WriteBlock(blamSound.Data);
                            }
                        }
                    }
                    else
                    {
                        permutationData = File.ReadAllBytes(cacheFileName);
                    }

                    permutation.PermutationChunks.Add(new PermutationChunk(currentSoundDataOffset, permutationData.Length));
                    currentSoundDataOffset += permutationData.Length;
                    pitchRange.Permutations.Add(permutation);

                    soundDataAggregate = soundDataAggregate.Concat(permutationData);
                }
            }

            sound.Promotion.LongestPermutationDuration = (uint)sound.SoundReference.MaximumPlayTime;
            sound.Promotion.TotalSampleSize            = totalSampleCount;

            //
            // Convert Blam extra info to ElDorado format
            //

            var extraInfo = new ExtraInfo()
            {
                LanguagePermutations       = new List <ExtraInfo.LanguagePermutation>(),
                EncodedPermutationSections = new List <ExtraInfo.EncodedPermutationSection>()
            };

            for (int u = 0; u < sound.SoundReference.PitchRangeCount; u++)
            {
                var pitchRange = BlamSoundGestalt.PitchRanges[sound.SoundReference.PitchRangeIndex + u];

                for (int i = 0; i < pitchRange.PermutationCount; i++)
                {
                    var permutation      = BlamSoundGestalt.GetPermutation(pitchRange.FirstPermutationIndex + i);
                    var permutationChunk = BlamSoundGestalt.GetPermutationChunk(permutation.FirstPermutationChunkIndex);

                    extraInfo.LanguagePermutations.Add(new ExtraInfo.LanguagePermutation
                    {
                        RawInfo = new List <ExtraInfo.LanguagePermutation.RawInfoBlock>
                        {
                            new ExtraInfo.LanguagePermutation.RawInfoBlock
                            {
                                SkipFractionName = StringId.Invalid,
                                UnknownList      = new List <ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown>
                                {
                                    new ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown
                                    {
                                        Unknown1 = permutationChunk.UnknownA,
                                        Unknown2 = permutationChunk.UnknownSize,
                                        Unknown3 = 0,
                                        Unknown4 = permutation.SampleSize,
                                        Unknown5 = 0,
                                        Unknown6 = permutationChunk.EncodedSize & 0xFFFF
                                    }
                                },
                                Compression          = 8,
                                ResourceSampleSize   = pitchRange.Permutations[i].SampleSize,
                                ResourceSampleOffset = (uint)pitchRange.Permutations[i].PermutationChunks[0].Offset,
                                SampleCount          = (uint)pitchRange.Permutations[i].PermutationChunks[0].EncodedSize & 0x3FFFFFF,
                                //SampleCount = (uint)Math.Floor(pitchRange.Permutations[i].SampleSize * 128000.0 / (8 * sound.SampleRate.GetSampleRateHz())),
                                Unknown24 = 480
                            }
                        }
                    });
                }
            }

            if (sound.SoundReference.ExtraInfoIndex != -1)
            {
                foreach (var section in BlamSoundGestalt.ExtraInfo[sound.SoundReference.ExtraInfoIndex].EncodedPermutationSections)
                {
                    var newSection = section.DeepClone();

                    foreach (var info in newSection.SoundDialogueInfo)
                    {
                        for (var i = ((info.MouthDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.MouthDataLength; i += 2)
                        {
                            Array.Reverse(newSection.EncodedData, (int)(info.MouthDataOffset + i), 2);
                        }

                        for (var i = ((info.LipsyncDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.LipsyncDataLength; i += 2)
                        {
                            Array.Reverse(newSection.EncodedData, (int)(info.LipsyncDataOffset + i), 2);
                        }
                    }

                    extraInfo.EncodedPermutationSections.Add(newSection);
                }
            }

            sound.ExtraInfo = new List <ExtraInfo> {
                extraInfo
            };

            //
            // Convert Blam languages to ElDorado format
            //

            if (sound.SoundReference.LanguageIndex != -1)
            {
                sound.Languages = new List <LanguageBlock>();

                foreach (var language in BlamSoundGestalt.Languages)
                {
                    sound.Languages.Add(new LanguageBlock
                    {
                        Language             = language.Language,
                        PermutationDurations = new List <LanguageBlock.PermutationDurationBlock>(),
                        PitchRangeDurations  = new List <LanguageBlock.PitchRangeDurationBlock>(),
                    });

                    //Add all the  Pitch Range Duration block (pitch range count dependent)

                    var curLanguage = sound.Languages.Last();

                    for (int i = 0; i < sound.SoundReference.PitchRangeCount; i++)
                    {
                        curLanguage.PitchRangeDurations.Add(language.PitchRangeDurations[sound.SoundReference.LanguageIndex + i]);
                    }

                    //Add all the Permutation Duration Block and adjust offsets

                    for (int i = 0; i < curLanguage.PitchRangeDurations.Count; i++)
                    {
                        var curPRD = curLanguage.PitchRangeDurations[i];

                        //Get current block count for new index
                        short newPermutationIndex = (short)curLanguage.PermutationDurations.Count();

                        for (int j = curPRD.PermutationStartIndex; j < curPRD.PermutationStartIndex + curPRD.PermutationCount; j++)
                        {
                            curLanguage.PermutationDurations.Add(language.PermutationDurations[j]);
                        }

                        //apply new index
                        curPRD.PermutationStartIndex = newPermutationIndex;
                    }
                }
            }

            //
            // Prepare resource
            //

            sound.Unused    = new byte[] { 0, 0, 0, 0 };
            sound.Unknown12 = 0;

            sound.Resource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1,
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.Sound,
                    DefinitionData           = new byte[20],
                    DefinitionAddress        = new CacheResourceAddress(CacheResourceAddressType.Definition, 536870912),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            var data = soundDataAggregate.ToArray();

            var resourceContext = new ResourceSerializationContext(CacheContext, sound.Resource);

            CacheContext.Serializer.Serialize(resourceContext,
                                              new SoundResourceDefinition
            {
                Data = new TagData(data.Length, new CacheResourceAddress(CacheResourceAddressType.Resource, 0))
            });

            var definitionFixup = new TagResourceGen3.ResourceFixup()
            {
                BlockOffset = 12,
                Address     = new CacheResourceAddress(CacheResourceAddressType.Resource, 1073741824)
            };

            sound.Resource.Resource.ResourceFixups.Add(definitionFixup);

            sound.Resource.ChangeLocation(ResourceLocation.Audio);
            var resource = sound.Resource;

            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            var cache = CacheContext.GetResourceCache(ResourceLocation.Audio);

            if (!resourceStreams.ContainsKey(ResourceLocation.Audio))
            {
                resourceStreams[ResourceLocation.Audio] = FlagIsSet(PortingFlags.Memory) ?
                                                          new MemoryStream() :
                                                          (Stream)CacheContext.OpenResourceCacheReadWrite(ResourceLocation.Audio);

                if (FlagIsSet(PortingFlags.Memory))
                {
                    using (var resourceStream = CacheContext.OpenResourceCacheRead(ResourceLocation.Audio))
                        resourceStream.CopyTo(resourceStreams[ResourceLocation.Audio]);
                }
            }

            resource.Page.Index = cache.Add(resourceStreams[ResourceLocation.Audio], data, out uint compressedSize);
            resource.Page.CompressedBlockSize   = compressedSize;
            resource.Page.UncompressedBlockSize = (uint)data.Length;
            resource.DisableChecksum();

            for (int i = 0; i < 4; i++)
            {
                sound.Resource.Resource.DefinitionData[i] = (byte)(sound.Resource.Page.UncompressedBlockSize >> (i * 8));
            }

            return(sound);
        }
예제 #12
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            if (args.Count == 2 && (args[0].ToLower() != "raw"))
            {
                return(false);
            }

            var file = "";

            if (args.Count == 1)
            {
                file = args[0];
            }
            else
            {
                file = args[1];
            }

            var resourceContext = new ResourceSerializationContext(CacheContext, Geometry.Resource);
            var definition      = CacheContext.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(resourceContext);

            if (args.Count == 2)
            {
                using (var edResourceStream = new MemoryStream())
                    using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian))
                    {
                        var directory = args[1];
                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }

                        var dataOutDir = directory;

                        for (var i = 0; i < definition.VertexBuffers.Count; i++)
                        {
                            edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset;

                            var vertexBuffer = definition.VertexBuffers[i].Definition;

                            dataOutDir = Path.Combine(directory, $"{i}_{vertexBuffer.Format}_{vertexBuffer.Count}");

                            using (EndianWriter output = new EndianWriter(File.OpenWrite(dataOutDir), EndianFormat.LittleEndian))
                            {
                                byte[] data = edResourceReader.ReadBytes((int)vertexBuffer.Data.Size);
                                output.WriteBlock(data);
                            }
                        }
                    }
            }
            else
            {
                //
                // Convert Blam data to ElDorado data
                //

                using (var fileStream = File.Create(file))
                    using (var fileWriter = new StreamWriter(fileStream))
                    {
                        using (var edResourceStream = new MemoryStream())
                            using (var edResourceReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian))
                            {
                                //
                                // Convert Blam vertex buffers
                                //

                                Console.Write("Converting vertex buffers...");
                                CacheContext.ExtractResource(Geometry.Resource, edResourceStream);

                                for (var i = 0; i < definition.VertexBuffers.Count; i++)
                                {
                                    edResourceStream.Position = definition.VertexBuffers[i].Definition.Data.Address.Offset;

                                    var vertexBuffer = definition.VertexBuffers[i].Definition;

                                    //fileWriter.WriteLine($"Offset = {vertexBuffer.Data.Address.Offset.ToString("X8")} Count = {vertexBuffer.Count} Size = {vertexBuffer.VertexSize}, Format = {vertexBuffer.Format.ToString()}");
                                    //fileWriter.WriteLine(Environment.NewLine);

                                    //fileWriter.WriteLine($"Vertex buffer index: {i}");

                                    switch (vertexBuffer.Format)
                                    {
                                    case VertexBufferFormat.TinyPosition:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"Position = ({edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")},{edResourceReader.ReadUInt16().ToString("X4")})");
                                            fileWriter.WriteLine($"Normal   = ({edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")},{edResourceReader.ReadByte().ToString("X2")})");
                                            fileWriter.WriteLine($"Color    = {edResourceReader.ReadUInt32().ToString("X8")}");
                                        }
                                        break;

                                    case VertexBufferFormat.StaticPerVertex:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + edResourceReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                            fileWriter.WriteLine(Environment.NewLine);
                                        }
                                        break;

                                    case VertexBufferFormat.Skinned:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{j}:");
                                            fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                            edResourceReader.ReadUInt32();
                                            edResourceReader.ReadUInt32();
                                        }
                                        break;

                                        /*
                                         * case VertexBufferFormat.Unknown1B:
                                         *  var goodCount = 0;
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      //fileWriter.WriteLine($"Index: {j}:");
                                         *      string values = $"({ edResourceReader.ReadSingle()},{ edResourceReader.ReadSingle()}," +
                                         *          $"{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()}" +
                                         *          $",{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()},{edResourceReader.ReadSingle()})";
                                         *      if(values != "(0,0,0,0,0,0,0,0,0)")
                                         *      {
                                         *          goodCount++;
                                         *          //fileWriter.WriteLine($"(1,2,3,4,5,6,7,8,9) = "+values);
                                         *      }
                                         *
                                         *
                                         *      /*
                                         *      fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle());
                                         *
                                         *  }
                                         *  //fileWriter.WriteLine($"Valid Unknown1B count = {goodCount}");
                                         *  break;
                                         *
                                         * case VertexBufferFormat.Unknown1A:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      //fileWriter.WriteLine($"Index: {j}:");
                                         *      //fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadUInt32().ToString("X8"));
                                         *      fileWriter.WriteLine($"(1,2,3) = ({edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")},{edResourceReader.ReadUInt32().ToString("X8")})");
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.Rigid:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j}:");
                                         *      fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.StaticPerPixel:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j} U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      //fileWriter.WriteLine(Environment.NewLine);
                                         *  }
                                         *  break;
                                         *
                                         * case VertexBufferFormat.AmbientPrt:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j} Blend weight = " + edResourceReader.ReadSingle());
                                         *      //fileWriter.WriteLine(Environment.NewLine);
                                         *  }
                                         *  break;
                                         *
                                         *
                                         * case VertexBufferFormat.World:
                                         *  for (var j = 0; j < vertexBuffer.Count; j++)
                                         *  {
                                         *      fileWriter.WriteLine($"{j}:");
                                         *      fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Tangent  X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *      fileWriter.WriteLine($"Binormal X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *  }
                                         *  break;
                                         *
                                         *
                                         *
                                         */
                                        /*
                                         *  case VertexBufferFormat.QuadraticPrt:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"A X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"B X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"C X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *
                                         *
                                         *  case VertexBufferFormat.Unknown1B:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Unknown 1 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 2 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 3 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 4 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 5 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 6 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 7 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 8 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Unknown 9 = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *  case VertexBufferFormat.Decorator:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Position X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Texcoord U = " + edResourceReader.ReadSingle() + " V = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"Normal   X = " + edResourceReader.ReadSingle() + " Y = " + edResourceReader.ReadSingle() + " Z = " + edResourceReader.ReadSingle());
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         *
                                         *  case VertexBufferFormat.LinearPrt:
                                         *      for (var j = 0; j < vertexBuffer.Count; j++)
                                         *      {
                                         *          fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                         *          fileWriter.WriteLine($"Hex : " + edResourceReader.ReadUInt32().ToString("X8"));
                                         *          fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                         *          fileWriter.WriteLine(Environment.NewLine);
                                         *      }
                                         *      break;
                                         */
                                    }

                                    //fileWriter.WriteLine($"End of Vertex Buffer index: {i}");

                                    //fileWriter.WriteLine(Environment.NewLine);
                                }
                            }
                    }
            }



            return(true);
        }
예제 #13
0
        private string ConvertToAudioFile(ICollection <byte> data, string path = null)
        {
            var tempFile = Path.GetTempFileName();

            byte[] footer;
            var    codec = _soundResourceGestalt.SoundPlatformCodecs[_sound.CodecIndex];

            switch (codec.Channel)
            {
            case Channel.Mono:
                footer = _monoFooter;
                break;

            case Channel.Stereo:
                footer = _stereoFooter;
                break;

            default:
                throw new NotImplementedException();
            }

            switch (_sound.Encoding)
            {
            case Encoding.XMA:
                using (var fileStream = new FileStream(tempFile, FileMode.OpenOrCreate))
                {
                    using (var writer = new EndianWriter(fileStream, Endian.BigEndian))
                    {
                        // Generate an XMA header
                        // ADAPTED FROM wwisexmabank - I DO NOT TAKE ANY CREDIT WHATSOEVER FOR THE FOLLOWING CODE.
                        // See http://hcs64.com/vgm_ripping.html for more information

                        // 'riff' chunk
                        writer.WriteInt32(0x52494646);                                 // 'RIFF'
                        writer.Endianness = Endian.LittleEndian;
                        writer.WriteInt32(data.Count + 0x34);
                        writer.Endianness = Endian.BigEndian;
                        writer.WriteInt32(0x57415645);

                        // 'data' chunk
                        writer.Endianness = Endian.BigEndian;
                        writer.WriteInt32(0x64617461);                                 // 'data'
                        writer.Endianness = Endian.LittleEndian;
                        writer.WriteInt32(data.Count);
                        writer.WriteBlock(data.ToArray());

                        // footer
                        writer.WriteBlock(footer);

                        // size
                        writer.SeekTo(0x04);
                        writer.WriteInt32((Int32)writer.Length - 0x08);
                    }
                }

                VariousFunctions.RunProgramSilently(@"A:\Xbox\Games\towav.exe",
                                                    string.Format("\"{0}\"", Path.GetFileName(tempFile)),
                                                    Path.GetDirectoryName(tempFile));

                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }

                tempFile = Path.ChangeExtension(tempFile, "wav");

                if (path != null)
                {
                    File.Move(tempFile, path);
                }

                return(path ?? tempFile);

            default:
                throw new NotImplementedException();
            }
        }
예제 #14
0
        private string ConvertToAudioFile(ICollection <byte> data, string path = null)
        {
            string towav = Path.Combine(VariousFunctions.GetApplicationLocation(), "helpers", "towav.exe");

            if (!File.Exists(towav))
            {
                MetroMessageBox.Show("Cannot Convert Sound", "Sounds cannot be converted because towav.exe is not present. Copy it to the \\helpers folder inside your Assembly installation.");
                return(null);
            }

            var tempFile = Path.GetTempFileName();

            byte[] footer;
            var    codec = _soundResourceTable.Codecs[_sound.CodecIndex];

            switch ((SoundEncoding)codec.Encoding)
            {
            case SoundEncoding.Mono:
                footer = _monoFooter;
                break;

            case SoundEncoding.Stereo:
                footer = _stereoFooter;
                break;

            default:
                throw new NotImplementedException();
            }

            switch ((SoundCompression)codec.Compression)
            {
            case SoundCompression.XMA2:
                using (var fileStream = new FileStream(tempFile, FileMode.OpenOrCreate))
                {
                    using (var writer = new EndianWriter(fileStream, Endian.BigEndian))
                    {
                        // Generate an XMA header
                        // ADAPTED FROM wwisexmabank - I DO NOT TAKE ANY CREDIT WHATSOEVER FOR THE FOLLOWING CODE.
                        // See http://hcs64.com/vgm_ripping.html for more information

                        // 'riff' chunk
                        writer.WriteInt32(0x52494646);                                 // 'RIFF'
                        writer.Endianness = Endian.LittleEndian;
                        writer.WriteInt32(data.Count + 0x34);
                        writer.Endianness = Endian.BigEndian;
                        writer.WriteInt32(0x57415645);

                        // 'data' chunk
                        writer.Endianness = Endian.BigEndian;
                        writer.WriteInt32(0x64617461);                                 // 'data'
                        writer.Endianness = Endian.LittleEndian;
                        writer.WriteInt32(data.Count);
                        writer.WriteBlock(data.ToArray());

                        // footer
                        writer.WriteBlock(footer);

                        // size
                        writer.SeekTo(0x04);
                        writer.WriteInt32((Int32)writer.Length - 0x08);
                    }
                }

                VariousFunctions.RunProgramSilently(towav,
                                                    string.Format("\"{0}\"", Path.GetFileName(tempFile)),
                                                    Path.GetDirectoryName(tempFile));

                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }

                tempFile = Path.ChangeExtension(tempFile, "wav");

                if (path != null)
                {
                    File.Move(tempFile, path);
                }

                return(path ?? tempFile);

            default:
                throw new NotImplementedException();
            }
        }
예제 #15
0
        /// <summary>
        /// Extracts an xWMA sound and converts it to WAV.
        /// </summary>
        /// <param name="reader">The stream to read from.</param>
        /// <param name="offset">The offset of the data to extract.</param>
        /// <param name="rifx">The RIFX data for the sound.</param>
        /// <param name="outPath">The path of the file to save to.</param>
        public static void ExtractXWMAToWAV(EndianReader reader, int offset, RIFX rifx, string outPath)
        {
            // Create a temporary file to write an XWMA to
            string tempFile = Path.GetTempFileName();

            try
            {
                using (EndianWriter output = new EndianWriter(File.OpenWrite(tempFile), EndianFormat.Big))
                {
                    // Generate a little-endian XWMA header
                    // TODO: move this into a class?
                    output.Write(0x52494646); // 'RIFF'

                    // Recompute the file size because the one Wwise gives us is trash
                    // fileSize = header size (always 0x2C) + dpds data size + data header size (always 0x8) + data size
                    int fileSize = 0x2C + rifx.SeekOffsets.Length * 0x4 + 0x8 + rifx.DataSize;
                    output.Format = EndianFormat.Little;
                    output.Write(fileSize);

                    output.Format = EndianFormat.Big;
                    output.Write((int)RIFFFormat.XWMA);

                    // Generate the 'fmt ' chunk
                    output.Write(0x666D7420); // 'fmt '
                    output.Format = EndianFormat.Little;
                    output.Write(0x18);       // Chunk size
                    output.Write(rifx.Codec);
                    output.Write(rifx.ChannelCount);
                    output.Write(rifx.SampleRate);
                    output.Write(rifx.BytesPerSecond);
                    output.Write(rifx.BlockAlign);
                    output.Write(rifx.BitsPerSample);

                    // Write the extradata
                    // Bytes 4 and 5 have to be flipped because they make up an int16
                    // TODO: add error checking to make sure the extradata is the correct size (0x6)
                    output.Write((short)0x6);
                    output.WriteBlock(rifx.ExtraData, 0, 4);
                    output.Write(rifx.ExtraData[5]);
                    output.Write(rifx.ExtraData[4]);

                    // Generate the 'dpds' chunk
                    // It's really just the 'seek' chunk from the original data but renamed
                    output.Format = EndianFormat.Big;
                    output.Write(0x64706473); // 'dpds'

                    output.Format = EndianFormat.Little;
                    output.Write(rifx.SeekOffsets.Length * 4); // One uint32 per offset
                    foreach (int seek in rifx.SeekOffsets)
                    {
                        output.Write(seek);
                    }

                    // 'data' chunk
                    output.Format = EndianFormat.Big;
                    output.Write(0x64617461); // 'data'
                    output.Format = EndianFormat.Little;
                    output.Write(rifx.DataSize);

                    // Copy the data chunk contents from the original RIFX
                    reader.SeekTo(offset + rifx.DataOffset);
                    StreamUtil.Copy(reader, output, rifx.DataSize);
                }

                // Convert it with xWMAEncode
                RunProgramSilently("Helpers/xWMAEncode.exe", "\"" + tempFile + "\" \"" + outPath + "\"", Directory.GetCurrentDirectory());
            }
            finally
            {
                // Delete the temporary XWMA file
                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }
            }
        }
예제 #16
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            if (args.Count == 2 && (args[0].ToLower() != "raw"))
            {
                return(false);
            }

            var file = "";

            if (args.Count == 1)
            {
                file = args[0];
            }
            else
            {
                file = args[1];
            }

            var definition = Cache.ResourceCache.GetRenderGeometryApiResourceDefinition(Geometry.Resource);

            if (args.Count == 2)
            {
                using (var edResourceStream = new MemoryStream())
                    using (var vertexReader = new EndianReader(edResourceStream, EndianFormat.LittleEndian))
                    {
                        var directory = args[1];
                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }

                        var dataOutDir = directory;

                        for (var i = 0; i < definition.VertexBuffers.Count; i++)
                        {
                            edResourceStream.Position = 0;

                            var vertexBuffer = definition.VertexBuffers[i].Definition;

                            dataOutDir = Path.Combine(directory, $"{i}_{vertexBuffer.Format}_{vertexBuffer.Count}");

                            using (EndianWriter output = new EndianWriter(File.OpenWrite(dataOutDir), EndianFormat.LittleEndian))
                            {
                                byte[] data = null;
                                output.WriteBlock(data);
                            }
                        }
                    }
            }
            else
            {
                using (var fileStream = File.Create(file))
                    using (var fileWriter = new StreamWriter(fileStream))
                    {
                        for (var i = 0; i < definition.VertexBuffers.Count; i++)
                        {
                            var vertexBuffer = definition.VertexBuffers[i].Definition;

                            using (var vertexStream = new MemoryStream(vertexBuffer.Data.Data))
                                using (var vertexReader = new EndianReader(vertexStream, EndianFormat.LittleEndian))
                                {
                                    switch (vertexBuffer.Format)
                                    {
                                    case VertexBufferFormat.TinyPosition:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"Position = ({vertexReader.ReadUInt16().ToString("X4")},{vertexReader.ReadUInt16().ToString("X4")},{vertexReader.ReadUInt16().ToString("X4")},{vertexReader.ReadUInt16().ToString("X4")})");
                                            fileWriter.WriteLine($"Normal   = ({vertexReader.ReadByte().ToString("X2")},{vertexReader.ReadByte().ToString("X2")},{vertexReader.ReadByte().ToString("X2")},{vertexReader.ReadByte().ToString("X2")})");
                                            fileWriter.WriteLine($"Color    = {vertexReader.ReadUInt32().ToString("X8")}");
                                        }
                                        break;

                                    case VertexBufferFormat.StaticPerVertex:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{vertexBuffer.Format} index: {j}:");
                                            fileWriter.WriteLine($"Texcoord = " + vertexReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + vertexReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + vertexReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + vertexReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"Texcoord = " + vertexReader.ReadUInt32().ToString("X8"));
                                            fileWriter.WriteLine($"End of {vertexBuffer.Format} index: {j}");
                                            fileWriter.WriteLine(Environment.NewLine);
                                        }
                                        break;

                                    case VertexBufferFormat.Skinned:
                                        for (var j = 0; j < vertexBuffer.Count; j++)
                                        {
                                            fileWriter.WriteLine($"{j}:");
                                            fileWriter.WriteLine($"Position X = " + vertexReader.ReadSingle() + " Y = " + vertexReader.ReadSingle() + " Z = " + vertexReader.ReadSingle());
                                            fileWriter.WriteLine($"Texcoord U = " + vertexReader.ReadSingle() + " V = " + vertexReader.ReadSingle());
                                            fileWriter.WriteLine($"Normal   X = " + vertexReader.ReadSingle() + " Y = " + vertexReader.ReadSingle() + " Z = " + vertexReader.ReadSingle());
                                            fileWriter.WriteLine($"Tangent  X = " + vertexReader.ReadSingle() + " Y = " + vertexReader.ReadSingle() + " Z = " + vertexReader.ReadSingle());
                                            fileWriter.WriteLine($"Binormal X = " + vertexReader.ReadSingle() + " Y = " + vertexReader.ReadSingle() + " Z = " + vertexReader.ReadSingle());
                                            vertexReader.ReadUInt32();
                                            vertexReader.ReadUInt32();
                                        }
                                        break;
                                    }
                                }
                        }
                    }
            }



            return(true);
        }
예제 #17
0
        public override object Execute(List <string> args)
        {
            string outDirectory = "";

            if (args.Count == 1)
            {
                outDirectory = args[0];
            }
            else if (args.Count == 0)
            {
                outDirectory = "Sounds";
            }
            else
            {
                return(false);
            }

            if (!Directory.Exists(outDirectory))
            {
                Console.Write("Destination directory does not exist. Create it? [y/n] ");
                var answer = Console.ReadLine().ToLower();

                if (answer.Length == 0 || !(answer.StartsWith("y") || answer.StartsWith("n")))
                {
                    return(false);
                }

                if (answer.StartsWith("y"))
                {
                    Directory.CreateDirectory(outDirectory);
                }
                else
                {
                    return(false);
                }
            }


            var resourceReference  = Definition.Resource;
            var resourceDefinition = Cache.ResourceCache.GetSoundResourceDefinition(resourceReference);

            if (resourceDefinition.Data == null)
            {
                Console.WriteLine("Invalid sound definition");
                return(false);
            }

            var dataReference = resourceDefinition.Data;

            byte[] soundData = dataReference.Data;

            if (Cache is GameCacheHaloOnlineBase)
            {
                for (int i = 0; i < Definition.PitchRanges.Count; i++)
                {
                    var pitchRange = Definition.PitchRanges[i];
                    for (int j = 0; j < pitchRange.Permutations.Count; j++)
                    {
                        var permutation = pitchRange.Permutations[j];
                        var filename    = Tag.Index.ToString("X8") + "_" + i.ToString() + "_" + j.ToString();

                        byte[] permutationData = new byte[permutation.PermutationChunks[0].EncodedSize & 0x3FFFFFF];
                        Array.Copy(soundData, permutation.PermutationChunks[0].Offset, permutationData, 0, permutationData.Length);

                        switch (Definition.PlatformCodec.Compression)
                        {
                        case Compression.PCM:
                            filename += ".wav";
                            break;

                        case Compression.MP3:
                            filename += ".mp3";
                            break;

                        case Compression.FSB4:
                            filename += ".fsb";
                            break;
                        }

                        var outPath = Path.Combine(outDirectory, filename);

                        using (EndianWriter writer = new EndianWriter(new FileStream(outPath, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                        {
                            var channelCount = Encoding.GetChannelCount(Definition.PlatformCodec.Encoding);
                            var sampleRate   = Definition.SampleRate.GetSampleRateHz();

                            switch (Definition.PlatformCodec.Compression)
                            {
                            case Compression.PCM:
                                WAVFile WAVfile = new WAVFile(permutationData, channelCount, sampleRate);
                                WAVfile.Write(writer);
                                break;

                            case Compression.MP3:
                            case Compression.FSB4:
                                writer.Write(permutationData);
                                break;
                            }
                        }
                    }
                }
            }
            else if (Cache.GetType() == typeof(GameCacheGen3))
            {
                if (BlamSoundGestalt == null)
                {
                    using (var stream = Cache.OpenCacheRead())
                        BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(Cache, stream);
                }


                for (int pitchRangeIndex = Definition.SoundReference.PitchRangeIndex; pitchRangeIndex < Definition.SoundReference.PitchRangeIndex + Definition.SoundReference.PitchRangeCount; pitchRangeIndex++)
                {
                    var relativePitchRangeIndex = pitchRangeIndex - Definition.SoundReference.PitchRangeIndex;
                    var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);

                    for (int i = 0; i < permutationCount; i++)
                    {
                        string    permutationName = $"{Tag.Name.Replace('\\', '_')}_{relativePitchRangeIndex}_{i}.mp3";
                        var       outPath         = Path.Combine(outDirectory, permutationName);
                        BlamSound blamSound       = SoundConverter.ConvertGen3Sound(Cache, BlamSoundGestalt, Definition, relativePitchRangeIndex, i, soundData);
                        using (EndianWriter output = new EndianWriter(new FileStream(outPath, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                        {
                            output.WriteBlock(blamSound.Data);
                        }
                    }
                }
            }


            Console.WriteLine("Done!");
            return(true);
        }
예제 #18
0
파일: FSB4.cs 프로젝트: jaron780/TagTool
 override public void Write(EndianWriter writer)
 {
     ArchiveHeader.WriteChunk(writer);
     File.WriteChunk(writer);
     writer.WriteBlock(Data);
 }
예제 #19
0
파일: DDSFile.cs 프로젝트: jaron780/TagTool
 public void Write(EndianWriter writer)
 {
     Header.Write(writer);
     writer.WriteBlock(BitmapData);
 }