using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using CsbBuilder.Project; using CsbBuilder.BuilderNode; using CsbBuilder.Serialization; using SonicAudioLib.CriMw; using SonicAudioLib.CriMw.Serialization; using SonicAudioLib.Archive; namespace CsbBuilder.Builder { public static class CsbBuilder { public static void Build(CsbProject project, string outputFileName) { CriCpkArchive cpkArchive = new CriCpkArchive(); DirectoryInfo outputDirectory = new DirectoryInfo(Path.GetDirectoryName(outputFileName)); List cueSheetTables = new List(); SerializationVersionInfoTable versionInfoTable = new SerializationVersionInfoTable(); cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(new List() { versionInfoTable }, CriTableWriterSettings.AdxSettings), Name = "INFO", TableType = 7, }); // Serialize cues. List cueTables = new List(); foreach (BuilderCueNode cueNode in project.CueNodes) { cueTables.Add(new SerializationCueTable { Name = cueNode.Name, Id = cueNode.Identifier, UserData = cueNode.UserComment, Flags = cueNode.Flags, SynthPath = cueNode.SynthReference, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(cueTables, CriTableWriterSettings.AdxSettings), Name = "CUE", TableType = 1, }); // Serialize synth tables. List synthTables = new List(); foreach (BuilderSynthNode synthNode in project.SynthNodes) { SerializationSynthTable synthTable = new SerializationSynthTable { SynthName = synthNode.Name, SynthType = (byte)synthNode.Type, ComplexType = (byte)synthNode.PlaybackType, Volume = synthNode.Volume, Pitch = synthNode.Pitch, DelayTime = synthNode.DelayTime, SControl = synthNode.SControl, EgDelay = synthNode.EgDelay, EgAttack = synthNode.EgAttack, EgHold = synthNode.EgHold, EgDecay = synthNode.EgDecay, EgRelease = synthNode.EgRelease, EgSustain = synthNode.EgSustain, FType = synthNode.FilterType, FCof1 = synthNode.FilterCutoff1, FCof2 = synthNode.FilterCutoff2, FReso = synthNode.FilterReso, FReleaseOffset = synthNode.FilterReleaseOffset, DryOName = synthNode.DryOName, Mtxrtr = synthNode.Mtxrtr, Dry0 = synthNode.Dry0, Dry1 = synthNode.Dry1, Dry2 = synthNode.Dry2, Dry3 = synthNode.Dry3, Dry4 = synthNode.Dry4, Dry5 = synthNode.Dry5, Dry6 = synthNode.Dry6, Dry7 = synthNode.Dry7, WetOName = synthNode.WetOName, Wet0 = synthNode.Wet0, Wet1 = synthNode.Wet1, Wet2 = synthNode.Wet2, Wet3 = synthNode.Wet3, Wet4 = synthNode.Wet4, Wet5 = synthNode.Wet5, Wet6 = synthNode.Wet6, Wet7 = synthNode.Wet7, Wcnct0 = synthNode.Wcnct0, Wcnct1 = synthNode.Wcnct1, Wcnct2 = synthNode.Wcnct2, Wcnct3 = synthNode.Wcnct3, Wcnct4 = synthNode.Wcnct4, Wcnct5 = synthNode.Wcnct5, Wcnct6 = synthNode.Wcnct6, Wcnct7 = synthNode.Wcnct7, VoiceLimitGroupName = synthNode.VoiceLimitGroupReference, VoiceLimitType = synthNode.VoiceLimitType, VoiceLimitPriority = synthNode.VoiceLimitPriority, VoiceLimitPhTime = synthNode.VoiceLimitProhibitionTime, VoiceLimitPcdlt = synthNode.VoiceLimitPcdlt, Pan3dVolumeOffset = synthNode.Pan3dVolumeOffset, Pan3dVolumeGain = synthNode.Pan3dVolumeGain, Pan3dAngleOffset = synthNode.Pan3dAngleOffset, Pan3dAngleGain = synthNode.Pan3dAngleGain, Pan3dDistanceOffset = synthNode.Pan3dDistanceOffset, Pan3dDistanceGain = synthNode.Pan3dDistanceGain, Dry0g = synthNode.Dry0g, Dry1g = synthNode.Dry1g, Dry2g = synthNode.Dry2g, Dry3g = synthNode.Dry3g, Dry4g = synthNode.Dry4g, Dry5g = synthNode.Dry5g, Dry6g = synthNode.Dry6g, Dry7g = synthNode.Dry7g, Wet0g = synthNode.Wet0g, Wet1g = synthNode.Wet1g, Wet2g = synthNode.Wet2g, Wet3g = synthNode.Wet3g, Wet4g = synthNode.Wet4g, Wet5g = synthNode.Wet5g, Wet6g = synthNode.Wet6g, Wet7g = synthNode.Wet7g, F1Type = synthNode.Filter1Type, F1CofOffset = synthNode.Filter1CutoffOffset, F1CofGain = synthNode.Filter1CutoffGain, F1ResoOffset = synthNode.Filter1ResoOffset, F1ResoGain = synthNode.Filter1ResoGain, F2Type = synthNode.Filter2Type, F2CofLowOffset = synthNode.Filter2CutoffLowerOffset, F2CofLowGain = synthNode.Filter2CutoffLowerGain, F2CofHighOffset = synthNode.Filter2CutoffHigherOffset, F2CofHighGain = synthNode.Filter2CutoffHigherGain, Probability = synthNode.PlaybackProbability, NumberLmtChildren = synthNode.NLmtChildren, Repeat = synthNode.Repeat, ComboTime = synthNode.ComboTime, ComboLoopBack = synthNode.ComboLoopBack, }; if (synthNode.Type == BuilderSynthType.Single) { synthTable.LinkName = synthNode.SoundElementReference; } else if (synthNode.Type == BuilderSynthType.WithChildren) { foreach (string trackReference in synthNode.Children) { synthTable.LinkName += trackReference + (char)0x0A; } } if (!string.IsNullOrEmpty(synthNode.AisacReference)) { BuilderAisacNode aisacNode = project.AisacNodes.First(aisac => aisac.Name == synthNode.AisacReference); synthTable.AisacSetName = aisacNode.AisacName + "::" + aisacNode.Name + (char)0x0A; } synthTables.Add(synthTable); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(synthTables, CriTableWriterSettings.AdxSettings), Name = "SYNTH", TableType = 2, }); List junks = new List(); // Serialize the sound elements. List soundElementTables = new List(); foreach (BuilderSoundElementNode soundElementNode in project.SoundElementNodes) { CriAaxArchive aaxArchive = new CriAaxArchive(); if (!string.IsNullOrEmpty(soundElementNode.Intro)) { aaxArchive.Add(new CriAaxEntry { Flag = CriAaxEntryFlag.Intro, FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Intro)), }); } if (!string.IsNullOrEmpty(soundElementNode.Loop)) { aaxArchive.Add(new CriAaxEntry { Flag = CriAaxEntryFlag.Loop, FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Loop)), }); } byte[] data = new byte[0]; if (soundElementNode.Streaming) { CriCpkEntry entry = new CriCpkEntry(); entry.Name = Path.GetFileName(soundElementNode.Name); entry.DirectoryName = Path.GetDirectoryName(soundElementNode.Name); entry.Id = (uint)cpkArchive.Count; entry.UpdateDateTime = DateTime.Now; entry.FilePath = new FileInfo(Path.GetTempFileName()); cpkArchive.Add(entry); aaxArchive.Save(entry.FilePath.FullName); junks.Add(entry.FilePath); } else { data = aaxArchive.Save(); } soundElementTables.Add(new SerializationSoundElementTable { Name = soundElementNode.Name, Data = data, FormatType = 0, SoundFrequency = soundElementNode.SampleRate, NumberChannels = soundElementNode.ChannelCount, Streaming = soundElementNode.Streaming, NumberSamples = soundElementNode.SampleCount, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(soundElementTables, CriTableWriterSettings.AdxSettings), Name = "SOUND_ELEMENT", TableType = 4, }); // Serialize the aisacs. List aisacTables = new List(); foreach (BuilderAisacNode aisacNode in project.AisacNodes) { List graphTables = new List(); foreach (BuilderAisacGraphNode graphNode in aisacNode.Graphs) { List pointTables = new List(); foreach (BuilderAisacPointNode pointNode in graphNode.Points) { pointTables.Add(new SerializationAisacPointTable { In = pointNode.X, Out = pointNode.Y, }); } graphTables.Add(new SerializationAisacGraphTable { Points = CriTableSerializer.Serialize(pointTables, CriTableWriterSettings.AdxSettings), Type = graphNode.Type, InMax = graphNode.MaximumX, InMin = graphNode.MinimumX, OutMax = graphNode.MaximumY, OutMin = graphNode.MinimumY, }); } aisacTables.Add(new SerializationAisacTable { Graph = CriTableSerializer.Serialize(graphTables, CriTableWriterSettings.AdxSettings), Name = aisacNode.AisacName, PathName = aisacNode.Name, Type = aisacNode.Type, RandomRange = aisacNode.RandomRange, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(aisacTables, CriTableWriterSettings.AdxSettings), Name = "ISAAC", TableType = 5, }); // Serialize the voice limit groups. List voiceLimitGroupTables = new List(); foreach (BuilderVoiceLimitGroupNode voiceLimitGroupNode in project.VoiceLimitGroupNodes) { voiceLimitGroupTables.Add(new SerializationVoiceLimitGroupTable { VoiceLimitGroupName = voiceLimitGroupNode.Name, VoiceLimitGroupNum = voiceLimitGroupNode.MaxAmountOfInstances, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(voiceLimitGroupTables, CriTableWriterSettings.AdxSettings), Name = "VOICE_LIMIT_GROUP", TableType = 6, }); // Finally, serialize the CSB file. CriTableSerializer.Serialize(outputFileName, cueSheetTables, CriTableWriterSettings.AdxSettings, MainForm.Settings.BufferSize); if (cpkArchive.Count > 0) { cpkArchive.Save(Path.ChangeExtension(outputFileName, "cpk"), MainForm.Settings.BufferSize); } foreach (FileInfo junk in junks) { junk.Delete(); } } } }