public override object Execute(List <string> args) { if (args.Count != 0) { return(false); } var soundDataAggregate = new byte[0].AsEnumerable(); int currentFileOffset = 0; int totalSampleCount = 0; int maxPermutationSampleCount = 0; int pitchRangeCount = GetPitchRangeCountUser(); if (pitchRangeCount <= 0) { return(false); } // // Get basic information on the sounds // if (pitchRangeCount > 1) { Definition.ImportType = ImportType.MultiLayer; } else { Definition.ImportType = ImportType.SingleLayer; } Definition.SampleRate.value = GetSoundSampleRateUser(); Definition.PlatformCodec.Compression = GetSoundCompressionUser(); Definition.PlatformCodec.Encoding = GetSoundEncodingUser(); Definition.PitchRanges = new List <PitchRange>(); // // For each pitch range, get all the permutations and append sound data. // for (int u = 0; u < pitchRangeCount; u++) { int permutationCount = GetPermutationCountUser(); if (permutationCount <= 0) { return(false); } var pitchRange = new PitchRange { ImportName = new StringId(5221), //|default| Unknown5 = -1, Unknown6 = -1, Unknown7 = -1, Unknown8 = -1, PermutationCount = (short)permutationCount, PitchRangeParameters = new PitchRangeParameter() }; pitchRange.PitchRangeParameters.UnknownBounds = new Bounds <short>(-32768, 32767); pitchRange.Permutations = new List <Permutation>(); // // Permutation section // for (int i = 0; i < permutationCount; i++) { string soundFile = GetPermutationFileUser(i); if (soundFile == null) { return(false); } int sampleCount = GetPermutationSampleCountUser(i); var perm = new Permutation { ImportName = StringId.Invalid, SampleSize = (uint)sampleCount }; if (i != 0) { perm.IsNotFirstPermutation = 1; } perm.PermutationNumber = (uint)i; var permutationData = File.ReadAllBytes(soundFile); perm.PermutationChunks = new List <PermutationChunk>(); var chunk = new PermutationChunk(currentFileOffset, permutationData.Length); perm.PermutationChunks.Add(chunk); currentFileOffset += permutationData.Length; totalSampleCount += sampleCount; if (maxPermutationSampleCount < sampleCount) { maxPermutationSampleCount = sampleCount; } soundDataAggregate = soundDataAggregate.Concat(permutationData); pitchRange.Permutations.Add(perm); } Definition.PitchRanges.Add(pitchRange); } Definition.Promotion.LongestPermutationDuration = (uint)(1000 * (double)maxPermutationSampleCount / (Definition.SampleRate.GetSampleRateHz())); Definition.Promotion.TotalSampleSize = (uint)totalSampleCount; // remove extra info for now Definition.ExtraInfo = new List <ExtraInfo>(); // // Create new resource // Console.Write("Creating new sound resource..."); var data = soundDataAggregate.ToArray(); Definition.Unknown12 = 0; using (var dataStream = new MemoryStream(data)) { var fileSize = (int)dataStream.Length; var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Resource); CacheContext.Serializer.Serialize(resourceContext, new SoundResourceDefinition { Data = new TagData(fileSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0)) }); Definition.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> { new TagResourceGen3.ResourceFixup { BlockOffset = 12, Address = new CacheResourceAddress(CacheResourceAddressType.Resource, 1073741824) } }, ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(), Unknown2 = 1 } }; Definition.Resource.ChangeLocation(ResourceLocation.ResourcesB); CacheContext.AddResource(Definition.Resource, dataStream); for (int i = 0; i < 4; i++) { Definition.Resource.Resource.DefinitionData[i] = (byte)(Definition.Resource.Page.UncompressedBlockSize >> (i * 8)); } Console.WriteLine("done."); } return(true); }
private Sound ConvertSound(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, Sound sound, string blamTag_Name) { if (BlamSoundGestalt == null) { BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(BlamCache, blamCacheStream); } 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 soundResource = BlamCache.ResourceCache.GetSoundResourceDefinition(sound.Resource); if (soundResource == null) { return(null); } var xmaData = soundResource.Data.Data; 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); } // fixup dialog indices, might need more work var firstPermutationChunk = BlamSoundGestalt.GetFirstPermutationChunk(permutationIndex); var newChunk = new PermutationChunk(currentSoundDataOffset, permutationData.Length, firstPermutationChunk.SoundDialogInfoIndex, firstPermutationChunk.Unknown, firstPermutationChunk.UnknownSize); permutation.PermutationChunks.Add(newChunk); 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 { SoundDialogInfoSize = permutationChunk.SoundDialogInfoIndex, Unknown1 = permutationChunk.Unknown, 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.Unknown12 = 0; var data = soundDataAggregate.ToArray(); var resourceDefinition = AudioUtils.CreateSoundResourceDefinition(data); var resourceReference = CacheContext.ResourceCache.CreateSoundResource(resourceDefinition); sound.Resource = resourceReference; return(sound); }
public override object Execute(List <string> args) { if (args.Count != 0) { return(false); } var soundDataAggregate = new byte[0].AsEnumerable(); int currentFileOffset = 0; int totalSampleCount = 0; int maxPermutationSampleCount = 0; int pitchRangeCount = GetPitchRangeCountUser(); if (pitchRangeCount <= 0) { return(false); } // // Get basic information on the sounds // if (pitchRangeCount > 1) { Definition.ImportType = ImportType.MultiLayer; } else { Definition.ImportType = ImportType.SingleLayer; } Definition.SampleRate.value = GetSoundSampleRateUser(); Definition.PlatformCodec.Compression = GetSoundCompressionUser(); Definition.PlatformCodec.Encoding = GetSoundEncodingUser(); Definition.PitchRanges = new List <PitchRange>(); // // For each pitch range, get all the permutations and append sound data. // for (int u = 0; u < pitchRangeCount; u++) { int permutationCount = GetPermutationCountUser(); if (permutationCount <= 0) { return(false); } var pitchRange = new PitchRange { ImportName = new StringId(5221), //|default| Unknown5 = -1, Unknown6 = -1, Unknown7 = -1, Unknown8 = -1, PermutationCount = (short)permutationCount, PitchRangeParameters = new PitchRangeParameter() }; pitchRange.PitchRangeParameters.UnknownBounds = new Bounds <short>(-32768, 32767); pitchRange.Permutations = new List <Permutation>(); // // Permutation section // for (int i = 0; i < permutationCount; i++) { string soundFile = GetPermutationFileUser(i); if (soundFile == null) { return(false); } int sampleCount = GetPermutationSampleCountUser(i); var perm = new Permutation { ImportName = StringId.Invalid, SampleSize = (uint)sampleCount }; if (i != 0) { perm.IsNotFirstPermutation = 1; } perm.PermutationNumber = (uint)i; var permutationData = File.ReadAllBytes(soundFile); perm.PermutationChunks = new List <PermutationChunk>(); var chunk = new PermutationChunk(currentFileOffset, permutationData.Length); perm.PermutationChunks.Add(chunk); currentFileOffset += permutationData.Length; totalSampleCount += sampleCount; if (maxPermutationSampleCount < sampleCount) { maxPermutationSampleCount = sampleCount; } soundDataAggregate = soundDataAggregate.Concat(permutationData); pitchRange.Permutations.Add(perm); } Definition.PitchRanges.Add(pitchRange); } Definition.Promotion.LongestPermutationDuration = (uint)(1000 * (double)maxPermutationSampleCount / (Definition.SampleRate.GetSampleRateHz())); Definition.Promotion.TotalSampleSize = (uint)totalSampleCount; // remove extra info for now Definition.ExtraInfo = new List <ExtraInfo>(); Definition.Unknown12 = 0; // // Create new resource // Console.Write("Creating new sound resource..."); var data = soundDataAggregate.ToArray(); var resourceDefinition = AudioUtils.CreateSoundResourceDefinition(data); var resourceReference = Cache.ResourceCache.CreateSoundResource(resourceDefinition); Definition.Resource = resourceReference; Console.WriteLine("done."); return(true); }
public override object Execute(List <string> args) { if (args.Count != 1) { return(false); } var resourceFile = new FileInfo(args[0]); var fileSize = 0; if (!resourceFile.Exists) { Console.WriteLine($"ERROR: File not found: \"{resourceFile.FullName}\""); return(true); } // // Create new resource // Console.Write("Creating new sound resource..."); Definition.Unknown12 = 0; using (var dataStream = resourceFile.OpenRead()) { fileSize = (int)dataStream.Length; var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Resource); CacheContext.Serializer.Serialize(resourceContext, new SoundResourceDefinition { Data = new TagData(fileSize, new CacheAddress(CacheAddressType.Resource, 0)) }); Definition.Resource = new PageableResource { Page = new RawPage { Index = -1 }, Resource = new TagResourceGen3 { ResourceType = TagResourceTypeGen3.Sound, DefinitionData = new byte[20], DefinitionAddress = new CacheAddress(CacheAddressType.Definition, 536870912), ResourceFixups = new List <TagResourceGen3.ResourceFixup> { new TagResourceGen3.ResourceFixup { BlockOffset = 12, Address = new CacheAddress(CacheAddressType.Resource, 1073741824) } }, ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(), Unknown2 = 1 } }; Definition.Resource.ChangeLocation(ResourceLocation.ResourcesB); CacheContext.AddResource(Definition.Resource, dataStream); for (int i = 0; i < 4; i++) { Definition.Resource.Resource.DefinitionData[i] = (byte)(Definition.Resource.Page.UncompressedBlockSize >> (i * 8)); } Console.WriteLine("done."); } // // Adjust tag definition to use correctly the sound file. // var chunkSize = (ushort)fileSize; var permutationChunk = new PermutationChunk(0, chunkSize); var permutation = Definition.PitchRanges[0].Permutations[0]; permutation.PermutationChunks = new List <PermutationChunk> { permutationChunk }; permutation.PermutationNumber = 0; permutation.SampleSize = 0; permutation.IsNotFirstPermutation = 0; Definition.PitchRanges[0].Permutations = new List <Permutation> { permutation }; Definition.PlatformCodec.Compression = Compression.MP3; return(true); }