internal ArrangementData ExtractArrangementData(Attributes2014 attr) { string sngFilePath = $"songs/bin/generic/{attr.SongXml.Substring(20)}.sng"; var entry = _archive.TOC.Where(x => x.Name.Equals(sngFilePath)).FirstOrDefault(); if (entry == null) { throw new Exception($"Could not find arrangement sng {_filePath}/{sngFilePath}"); } ArrangementData data = null; _archive.InflateEntry(entry); entry.Data.Position = 0; var sng = Sng2014File.ReadSng(entry.Data, new RocksmithToolkitLib.Platform(RocksmithToolkitLib.GamePlatform.Pc, RocksmithToolkitLib.GameVersion.RS2014)); if (sng == null) { throw new Exception($"Could not read sng {_filePath}{sngFilePath}"); } data = new ArrangementData(sng); entry.Dispose(); return(data); }
/// <summary> /// Extracts a 256x256 bitmap album art from PsarcLoader /// </summary> /// <param name="loader"></param> /// <param name="artFile"></param> /// <returns></returns> internal Bitmap ExtractAlbumArt(Attributes2014 attr) { //Select the correct entry and load it into the memory stream using (MemoryStream ms = ExtractEntryData(x => (x.Name == "gfxassets/album_art/" + attr.AlbumArt.Substring(14) + "_256.dds"))) { //Create a Pfim image from memory stream Pfim.Dds img = Pfim.Dds.Create(ms, new Pfim.PfimConfig()); //Create bitmap Bitmap bm = new Bitmap(img.Width, img.Height); //Convert Pfim image to bitmap int bytesPerPixel = img.BytesPerPixel; for (int i = 0; i < img.Data.Length; i += bytesPerPixel) { //Calculate pixel X and Y coordinates int x = (i / bytesPerPixel) % img.Width; int y = (i / bytesPerPixel) / img.Width; //Get color from the Pfim image data array Color c = Color.FromArgb(255, img.Data[i + 2], img.Data[i + 1], img.Data[i]); //Set pixel in bitmap bm.SetPixel(x, y, c); } //Return bitmap return(bm); } }
public void GenerateChords(Attributes2014 attribute, Song2014 song) { // Some ODLC contain JSON Chords errors, this method is producing workable results // // USING song.Levels[difficulty].HandShapes METHOD // the handshape data can be used to obtain chordIds // (more efficient less data to iterate through) // //"Chords" : { // "DiffLevelID" : {//used to display which chord is set at current lvl. // "SectionID" : [// >= 0 // ChordID, // ChordID // ] // }, // } if (song.Sections == null) { return; } attribute.Chords = new Dictionary <string, Dictionary <string, List <int> > >(); for (int difficulty = 0; difficulty < song.Levels.Length; difficulty++) { var chords = song.Levels[difficulty].HandShapes; var sectionId = new Dictionary <string, List <int> >(); var chordId = new List <int>(); for (int section = 0; section < song.Sections.Length; section++) { var sectionNumber = song.Sections[section].Number; var starTime = song.Sections[section].StartTime; var endTime = song.Sections[Math.Min(section + 1, song.Sections.Length - 1)].StartTime; // iterate through chords in handshapes in the difficulty level foreach (var chord in chords) { if (chord.StartTime >= starTime && chord.EndTime < endTime) //in range { chordId.Add(chord.ChordId); } } if (chordId.Count > 0) { // always ordered in ODLC List <int> distinctChordIds = chordId.Distinct().OrderBy(x => x).ToList(); sectionId.Add(section.ToString(), distinctChordIds); } chordId = new List <int>(); } if (sectionId.Keys.Count > 0) { attribute.Chords.Add(difficulty.ToString(), sectionId); } } }
public AttributesHeader2014(Attributes2014 attributes) { foreach (PropertyInfo prop in attributes.GetType().GetProperties()) { if (GetType().GetProperty(prop.Name) != null) { GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(attributes, null), null); } } }
private void convertSngXmlButton_Click(object sender, EventArgs e) { if (String.IsNullOrEmpty(ConverterSngXmlFile)) { MessageBox.Show(String.Format("File not found: {0}: ", ConverterSngXmlFile), MESSAGEBOX_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Error); sngXmlTB.Focus(); return; } if (sng2xmlRadio.Checked) { if (String.IsNullOrEmpty(ConverterManifestFile)) { MessageBox.Show("No manifest file was entered. The song xml file will be generated without song informations like song title, album, artist, tone names, etc.", MESSAGEBOX_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Error); } Attributes2014 att = null; if (ConverterArrangementType != ArrangementType.Vocal && !String.IsNullOrEmpty(ConverterManifestFile)) { att = Manifest2014 <Attributes2014> .LoadFromFile(ConverterManifestFile).Entries.ToArray()[0].Value.ToArray()[0].Value; } var sng = Sng2014File.LoadFromFile(ConverterSngXmlFile, ConverterPlatform); var outputFile = Path.Combine(Path.GetDirectoryName(ConverterSngXmlFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(ConverterSngXmlFile))); using (FileStream outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite)) { dynamic xml = null; if (ConverterArrangementType == ArrangementType.Vocal) { xml = new Vocals(sng); } else { xml = new Song2014(sng, att ?? null); } xml.Serialize(outputStream); MessageBox.Show(String.Format("XML file was generated! {0}It was saved on same location of sng file specified.", Environment.NewLine), MESSAGEBOX_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Information); } } else if (xml2sngRadio.Checked) { var outputFile = Path.Combine(Path.GetDirectoryName(ConverterSngXmlFile), String.Format("{0}.sng", Path.GetFileNameWithoutExtension(ConverterSngXmlFile))); using (FileStream outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite)) { Sng2014File sng = Sng2014File.ConvertXML(ConverterSngXmlFile, ConverterArrangementType); sng.WriteSng(outputStream, ConverterPlatform); } MessageBox.Show(String.Format("SNG file was generated! {0}It was saved on same location of xml file specified.", Environment.NewLine), MESSAGEBOX_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Information); } }
private static List <Tone2014> ReadFromManifest(string manifestFilePath) { List <Tone2014> tones = new List <Tone2014>(); Attributes2014 jsonManifestAttributes = Manifest2014 <Attributes2014> .LoadFromFile(manifestFilePath).Entries.ToArray()[0].Value.ToArray()[0].Value; if (jsonManifestAttributes.ArrangementName != ArrangementName.Vocals.ToString() && jsonManifestAttributes.Tones != null) { tones.AddRange(jsonManifestAttributes.Tones); } return(tones); }
// method only produces output when arrangement has multitones internal static SongTone2014[] Parse(Sng2014HSL.ToneSection toneSection, Attributes2014 attr = null) { var tones = new SongTone2014[toneSection.Count]; for (var i = 0; i < toneSection.Count; i++) { var tone = new SongTone2014 { Id = toneSection.Tones[i].ToneId, Time = toneSection.Tones[i].Time }; if (attr != null) { // Get tone name switch (tone.Id) { case 0: tone.Name = attr.Tone_A; break; case 1: tone.Name = attr.Tone_B; break; case 2: tone.Name = attr.Tone_C; break; case 3: tone.Name = attr.Tone_D; break; default: tone.Name = "importedtone_" + tone.Id; break; } } else { tone.Name = "importedtone_" + tone.Id; } tones[i] = tone; } return(tones); }
public void GenerateTuningData(Attributes2014 attribute, dynamic song) { if (song.Tuning == null) { return; } attribute.Tuning = song.Tuning; var tuning = new TuningDefinition(); var tuningName = tuning.NameFromStrings(attribute.Tuning); if (tuningName == "E Standard") { attribute.ArrangementProperties.StandardTuning = 1; } else { attribute.ArrangementProperties.StandardTuning = 0; } }
/// <summary> /// Generates the techniques. /// </summary> /// <remarks> /// "Techniques" : { /// "DiffLevelID" : {//used to display which techs are set at current lvl. /// "SetionID" : [// > 0 /// TechID, //required base tech for extended tech(?) /// TechID /// ] /// }, /// } /// </remarks> /// <param name="attribute">Attribute.</param> /// <param name="song">Song.</param> public void GenerateTechniques(Attributes2014 attribute, Song2014 song) { if (song.Sections == null) { return; } attribute.Techniques = new Dictionary <string, Dictionary <string, List <int> > >(); for (int l = 0, s = 0, sectionsL = song.Sections.Length, levelsL = song.Levels.Length; l < levelsL; l++, s = 0) { // var shapes = song.Levels[l].HandShapes; // var chords = song.Levels[l].Chords; var notes = song.Levels[l].Notes; var t = new List <int>(); var techs = new Dictionary <string, List <int> >(); foreach (var n in notes) {//note should be in section range var starTime = song.Sections[s].StartTime; var endTime = song.Sections[Math.Min(s + 1, sectionsL - 1)].StartTime; if (n.Time > starTime && n.Time <= endTime)//in range { t.AddRange(getNoteTech(n)); } else if (n.Time > endTime)//at next section { s++; if (t.Count > 0) { techs.Add(s.ToString(), t.Distinct().ToList()); t = new List <int>(); } } } if (techs.Values.Count > 0) { attribute.Techniques.Add(l.ToString(), techs.Distinct().ToDictionary(x => x.Key, x => x.Value)); } } }
public void GenerateTuningData(Attributes2014 attribute, dynamic song) { // packer currently does very limited error checking (used mainly by advanced toolkit users) // this is a good place to ensure manifest data is the same as song xml data if (song.Version == "7") { if (song.CentOffset == null) { song.CentOffset = 0.0; } attribute.CentOffset = Convert.ToDouble(song.CentOffset); } if (song.Tuning == null) { song.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } } ; attribute.Tuning = song.Tuning; var tuning = new TuningDefinition(); var tuningName = tuning.NameFromStrings(attribute.Tuning); if (tuningName == "E Standard") { attribute.ArrangementProperties.StandardTuning = 1; } else { attribute.ArrangementProperties.StandardTuning = 0; } }
public Arrangement(Attributes2014 attr, string xmlSongFile) { var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile(); this.SongFile.File = ""; this.SongXml = new SongXML(); this.SongXml.File = xmlSongFile; //Tuning TuningDefinition tuning = null; switch ((ArrangementName)attr.ArrangementType) { case ArrangementName.Lead: case ArrangementName.Rhythm: case ArrangementName.Combo: this.ArrangementType = Sng.ArrangementType.Guitar; tuning = TuningDefinitionRepository.Instance().Select(song.Tuning, GameVersion.RS2014); break; case ArrangementName.Bass: this.ArrangementType = Sng.ArrangementType.Bass; // TODO: trying to fix bass tuning issue tuning = TuningDefinitionRepository.Instance().Select(song.Tuning, GameVersion.RS2014); // tuning = TuningDefinitionRepository.Instance().SelectForBass(song.Tuning, GameVersion.RS2014); break; case ArrangementName.Vocals: this.ArrangementType = Sng.ArrangementType.Vocal; break; } if (tuning == null) { tuning = new TuningDefinition(); tuning.UIName = tuning.Name = tuning.NameFromStrings(song.Tuning, this.ArrangementType == Sng.ArrangementType.Bass); tuning.Custom = true; tuning.GameVersion = GameVersion.RS2014; tuning.Tuning = song.Tuning; TuningDefinitionRepository.Instance().Add(tuning, true); } this.Tuning = tuning.UIName; this.TuningStrings = tuning.Tuning; this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) this.TuningPitch = attr.CentOffset.Cents2Frequency(); //Properties this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); //Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) throw new DataException("RS2012 CDLC has extraneous tone data."); } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) continue; // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangment file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) this.ToneBase = song.ToneBase = attr.Tone_Base; if (attr.Tone_A != null && jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) this.ToneA = song.ToneA = attr.Tone_A; if (attr.Tone_B != null && jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (attr.Tone_C != null && jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (attr.Tone_D != null && jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") xmlTone.Name = attr.Tone_A; if (xmlTone.Name == "ToneB") xmlTone.Name = attr.Tone_B; if (xmlTone.Name == "ToneC") xmlTone.Name = attr.Tone_C; if (xmlTone.Name == "ToneD") xmlTone.Name = attr.Tone_D; if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().Contains(xmlTone.Name.ToLower())) { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } if (song.Tones == null && toneId > 0) throw new InvalidDataException("Custom tones were not set properly in EOF" + Environment.NewLine + "Please reauthor XML arrangement in EOF and fix custom tone consistency."); } // write changes to xml arrangement using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream); } }
public Arrangement(Attributes2014 attr, string xmlSongFile) { var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile(); this.SongFile.File = ""; this.SongXml = new SongXML(); this.SongXml.File = xmlSongFile; //Tuning TuningDefinition tuning = null; switch ((ArrangementName)attr.ArrangementType) { case ArrangementName.Lead: case ArrangementName.Rhythm: case ArrangementName.Combo: this.ArrangementType = Sng.ArrangementType.Guitar; tuning = TuningDefinitionRepository.Instance().Select(song.Tuning, GameVersion.RS2014); break; case ArrangementName.Bass: this.ArrangementType = Sng.ArrangementType.Bass; // TODO: trying to fix bass tuning issue tuning = TuningDefinitionRepository.Instance().Select(song.Tuning, GameVersion.RS2014); // tuning = TuningDefinitionRepository.Instance().SelectForBass(song.Tuning, GameVersion.RS2014); break; case ArrangementName.Vocals: this.ArrangementType = Sng.ArrangementType.Vocal; break; } if (tuning == null) { tuning = new TuningDefinition(); tuning.UIName = tuning.Name = tuning.NameFromStrings(song.Tuning, this.ArrangementType == Sng.ArrangementType.Bass); tuning.Custom = true; tuning.GameVersion = GameVersion.RS2014; tuning.Tuning = song.Tuning; TuningDefinitionRepository.Instance().Add(tuning, true); } this.Tuning = tuning.UIName; this.TuningStrings = tuning.Tuning; this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) { this.TuningPitch = attr.CentOffset.Cents2Frequency(); } //Properties this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); //Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) { throw new DataException("RS2012 CDLC has extraneous tone data."); } } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) { continue; } // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangment file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) { this.ToneBase = song.ToneBase = attr.Tone_Base; } if (jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) { this.ToneA = song.ToneA = attr.Tone_A; } if (jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) { foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") { xmlTone.Name = attr.Tone_A; } if (xmlTone.Name == "ToneB") { xmlTone.Name = attr.Tone_B; } if (xmlTone.Name == "ToneC") { xmlTone.Name = attr.Tone_C; } if (xmlTone.Name == "ToneD") { xmlTone.Name = attr.Tone_D; } if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().Contains(xmlTone.Name.ToLower())) { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } } if (song.Tones == null && toneId > 0) { throw new InvalidDataException("Custom tones were not set properly in EOF" + Environment.NewLine + "Please reauthor XML arrangement in EOF and fix custom tone consistency."); } } // write changes to xml arrangement using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream); } }
/// <summary> /// Unpack the specified File, returns unpacked dir. /// </summary> /// <param name="sourceFileName">Source file path.</param> /// <param name="savePath">Save path.</param> /// <param name="decodeAudio">If set to <c>true</c> decode audio.</param> /// <param name="overwriteSongXml">If set to <c>true</c> overwrite existing song (EOF) xml with SNG data</param> /// <param name="predefinedPlatform">Predefined source platform.</param> public static string Unpack(string sourceFileName, string savePath, bool decodeAudio = false, bool overwriteSongXml = false, Platform predefinedPlatform = null) { Platform platform = sourceFileName.GetPlatform(); if (predefinedPlatform != null && predefinedPlatform.platform != GamePlatform.None && predefinedPlatform.version != GameVersion.None) { platform = predefinedPlatform; } var fnameWithoutExt = Path.GetFileNameWithoutExtension(sourceFileName); if (platform.platform == GamePlatform.PS3) { fnameWithoutExt = fnameWithoutExt.Substring(0, fnameWithoutExt.LastIndexOf(".")); } var unpackedDir = Path.Combine(savePath, String.Format("{0}_{1}", fnameWithoutExt, platform.platform)); if (Directory.Exists(unpackedDir)) { DirectoryExtension.SafeDelete(unpackedDir); } var useCryptography = platform.version == GameVersion.RS2012; // Cryptography way is used only for PC in Rocksmith 1 switch (platform.platform) { case GamePlatform.Pc: case GamePlatform.Mac: if (platform.version == GameVersion.RS2014) { using (var inputStream = File.OpenRead(sourceFileName)) ExtractPSARC(sourceFileName, savePath, inputStream, platform); } else { using (var inputFileStream = File.OpenRead(sourceFileName)) using (var inputStream = new MemoryStream()) { if (useCryptography) { RijndaelEncryptor.DecryptFile(inputFileStream, inputStream, RijndaelEncryptor.DLCKey); } else { inputFileStream.CopyTo(inputStream); } ExtractPSARC(sourceFileName, savePath, inputStream, platform); } } break; case GamePlatform.XBox360: UnpackXBox360Package(sourceFileName, savePath, platform); break; case GamePlatform.PS3: UnpackPS3Package(sourceFileName, savePath, platform); break; case GamePlatform.None: throw new InvalidOperationException("Platform not found :("); } // DECODE AUDIO if (decodeAudio) { GlobalExtension.ShowProgress("Decoding Audio ...", 50); var audioFiles = Directory.EnumerateFiles(unpackedDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".ogg") || s.EndsWith(".wem")); foreach (var file in audioFiles) { var outputAudioFileName = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_fixed{1}", Path.GetFileNameWithoutExtension(file), ".ogg")); OggFile.Revorb(file, outputAudioFileName, Path.GetDirectoryName(Application.ExecutablePath), Path.GetExtension(file).GetWwiseVersion()); } //GlobalExtension.HideProgress(); } // for debugging //overwriteSongXml = false; // Extract XML from SNG and check it against the EOF XML (correct bass tuning from older toolkit/EOF xml files) if (platform.version == GameVersion.RS2014) { var sngFiles = Directory.EnumerateFiles(unpackedDir, "*.sng", SearchOption.AllDirectories).ToList(); var step = Math.Round(1.0 / (sngFiles.Count + 2) * 100, 3); double progress = 0; GlobalExtension.ShowProgress("Extracting XML from SNG ..."); foreach (var sngFile in sngFiles) { var xmlEofFile = Path.Combine(Path.GetDirectoryName(sngFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(sngFile))); xmlEofFile = xmlEofFile.Replace(String.Format("bin{0}{1}", Path.DirectorySeparatorChar, platform.GetPathName()[1].ToLower()), "arr"); var xmlSngFile = xmlEofFile.Replace(".xml", ".sng.xml"); var arrType = ArrangementType.Guitar; if (Path.GetFileName(xmlSngFile).ToLower().Contains("vocal")) { arrType = ArrangementType.Vocal; } Attributes2014 att = null; if (arrType != ArrangementType.Vocal) { var jsonFiles = Directory.EnumerateFiles(unpackedDir, String.Format("{0}.json", Path.GetFileNameWithoutExtension(sngFile)), SearchOption.AllDirectories).FirstOrDefault(); if (!String.IsNullOrEmpty(jsonFiles) && jsonFiles.Any()) { att = Manifest2014 <Attributes2014> .LoadFromFile(jsonFiles).Entries.ToArray()[0].Value.ToArray()[0].Value; } } var sngContent = Sng2014File.LoadFromFile(sngFile, platform); using (var outputStream = new FileStream(xmlSngFile, FileMode.Create, FileAccess.ReadWrite)) { dynamic xmlContent = null; if (arrType == ArrangementType.Vocal) { xmlContent = new Vocals(sngContent); } else { xmlContent = new Song2014(sngContent, att); } xmlContent.Serialize(outputStream); } // correct old toolkit/EOF xml (tuning) issues ... sync with SNG data if (File.Exists(xmlEofFile) && !overwriteSongXml && arrType != ArrangementType.Vocal) { var eofSong = Song2014.LoadFromFile(xmlEofFile); var sngSong = Song2014.LoadFromFile(xmlSngFile); if (eofSong.Tuning != sngSong.Tuning) { eofSong.Tuning = sngSong.Tuning; var xmlComments = Song2014.ReadXmlComments(xmlEofFile); using (var stream = File.Open(xmlEofFile, FileMode.Create)) eofSong.Serialize(stream, true); Song2014.WriteXmlComments(xmlEofFile, xmlComments, customComment: "Synced with SNG file"); } File.Delete(xmlSngFile); } else { if (arrType != ArrangementType.Vocal) { Song2014.WriteXmlComments(xmlSngFile, customComment: "Generated from SNG file"); } File.Copy(xmlSngFile, xmlEofFile, true); File.Delete(xmlSngFile); } progress += step; GlobalExtension.UpdateProgress.Value = (int)progress; } //GlobalExtension.HideProgress(); } return(unpackedDir); }
/// <summary> /// Fill Arrangement 2014 from json and xml. /// </summary> /// <param name="attr"></param> /// <param name="xmlSongFile"></param> /// <param name="ignoreMultitoneException"> </param> public Arrangement(Attributes2014 attr, string xmlSongFile, bool ignoreMultitoneException = false) { var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile { File = "" }; this.SongXml = new SongXML { File = xmlSongFile }; //Properties Debug.Assert(attr.ArrangementType != null, "Missing information from manifest (ArrangementType)"); SetArrType(attr.ArrangementType); this.ArrangementPropeties = attr.ArrangementProperties; this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; //Filter out showlights\vocals if (ArrangementType != ArrangementType.Guitar && ArrangementType != ArrangementType.Bass) return; //Tuning DetectTuning(song); this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) this.TuningPitch = attr.CentOffset.Cents2Frequency(); // save xml comments this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); //Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) throw new DataException("RS2012 CDLC has extraneous tone data."); } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) continue; // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangement file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) this.ToneBase = song.ToneBase = attr.Tone_Base; if (attr.Tone_A != null && jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) this.ToneA = song.ToneA = attr.Tone_A; if (attr.Tone_B != null && jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (attr.Tone_C != null && jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (attr.Tone_D != null && jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") xmlTone.Name = attr.Tone_A; if (xmlTone.Name == "ToneB") xmlTone.Name = attr.Tone_B; if (xmlTone.Name == "ToneC") xmlTone.Name = attr.Tone_C; if (xmlTone.Name == "ToneD") xmlTone.Name = attr.Tone_D; if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().EndsWith(xmlTone.Name.ToLower())) //todo: SAMENAME tone fix? { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } // song.Tones => id, name, time to apply tone is missing when song.Tones == null if (song.Tones == null && toneId > 0) { // convert the corrupt multitone to a single tone instead of throwing exception if (ignoreMultitoneException) song.Tones = new SongTone2014[0]; // => song.Tones.Length == 0 else throw new InvalidDataException("Tone data is missing in CDLC and multitones will not change properly in game." + Environment.NewLine + "Please re-author XML arrangements in EOF and repair multitones name and time changes."); } } // convert corrupt multitone to single tone and/or cleanup/repair old toolkit single tone // ToneA in single tone ODLC is null/empty if ((song.Tones == null || song.Tones.Length == 0) && !String.IsNullOrEmpty(song.ToneA)) { song.ToneA = song.ToneB = song.ToneC = String.Empty; song.ToneBase = attr.Tone_Base; this.ToneBase = attr.Tone_Base; this.ToneA = this.ToneB = this.ToneC = String.Empty; } // write changes to xml arrangement (w/o comments) using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream, true); // write comments back to xml now so they are available for debugging (used for Guitar and Bass) Song2014.WriteXmlComments(xmlSongFile, XmlComments, writeNewVers: false); } }
public AttributesHeader2014(Attributes2014 attributes) { foreach (PropertyInfo prop in attributes.GetType().GetProperties()) if (GetType().GetProperty(prop.Name) != null) GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(attributes, null), null); }
static int Main(string[] args) { var arguments = DefaultArguments(); var options = GetOptions(arguments); try { options.Parse(args); if (arguments.ShowHelp) { options.WriteOptionDescriptions(Console.Out); return(0); } if (!arguments.Pack && !arguments.Unpack && !arguments.Sng2Xml && !arguments.Xml2Sng) { ShowHelpfulError("Must especify a primary command as 'pack', 'unpack', 'sng2xml' or 'xml2sng'."); return(1); } if (arguments.Input == null && arguments.Input.Length <= 0) { ShowHelpfulError("Must specify at least one input file."); return(1); } if (arguments.Sng2Xml && arguments.Manifest == null && arguments.Manifest.Length <= 0) { Console.WriteLine("No manifest file was entered. The song xml file will be generated without song informations like song title, album, artist, tone names, etc."); } var srcFiles = new List <string>(); foreach (var name in arguments.Input) { if (name.IsDirectory()) { srcFiles.AddRange(Directory.EnumerateFiles(Path.GetFullPath(name), "*.sng", SearchOption.AllDirectories)); } if (File.Exists(name)) { srcFiles.Add(name); } } var errorCount = 0; var indexCount = 0; foreach (string inputFile in srcFiles) { if (!File.Exists(inputFile)) { Console.WriteLine(String.Format("File '{0}' doesn't exists.", inputFile)); continue; } if (arguments.Unpack || arguments.Sng2Xml) { if (Path.GetExtension(inputFile) != ".sng") { Console.WriteLine(String.Format("File '{0}' is not support. \nOnly *.sng are supported on this command.", inputFile)); continue; } } if (arguments.Pack || arguments.Unpack) { var outputFile = Path.Combine(Path.GetDirectoryName(inputFile), String.Format("{0}_{1}.sng", Path.GetFileNameWithoutExtension(inputFile), (arguments.Unpack) ? "decrypted" : "encrypted")); using (FileStream inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read)) using (FileStream outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite)) { if (arguments.Pack) { Sng2014File.PackSng(inputStream, outputStream, new Platform(arguments.Platform, GameVersion.RS2014)); } else if (arguments.Unpack) { Sng2014File.UnpackSng(inputStream, outputStream, new Platform(arguments.Platform, GameVersion.RS2014)); } } } else if (arguments.Sng2Xml) { Attributes2014 att = null; if (arguments.ArrangementType != ArrangementType.Vocal && arguments.Manifest != null && arguments.Manifest.Length > indexCount) { att = Manifest2014 <Attributes2014> .LoadFromFile(arguments.Manifest[indexCount]).Entries.ToArray()[0].Value.ToArray()[0].Value; } var sng = Sng2014File.LoadFromFile(inputFile, new Platform(arguments.Platform, GameVersion.RS2014)); var outputFile = Path.Combine(Path.GetDirectoryName(inputFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(inputFile))); using (FileStream outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite)) { dynamic xml = null; if (arguments.ArrangementType == ArrangementType.Vocal) { xml = new Vocals(sng); } else { xml = new Song2014(sng, att ?? null); } xml.Serialize(outputStream); } } else if (arguments.Xml2Sng) { var outputFile = Path.Combine(Path.GetDirectoryName(inputFile), String.Format("{0}.sng", Path.GetFileNameWithoutExtension(inputFile))); using (FileStream outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite)) { Sng2014File sng = Sng2014File.ConvertXML(inputFile, arguments.ArrangementType); sng.WriteSng(outputStream, new Platform(arguments.Platform, GameVersion.RS2014)); } } } if (errorCount == 0) { Console.WriteLine("Process successfully completed!"); } else if (errorCount > 0 && errorCount < srcFiles.Count) { Console.WriteLine("Process completed with errors!"); } else { Console.WriteLine("An error occurred!"); } } catch (OptionException ex) { ShowHelpfulError(ex.Message); return(1); } return(0); }
public Arrangement(Attributes2014 attr, string xmlSongFile) { var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile(); this.SongFile.File = ""; this.SongXml = new SongXML(); this.SongXml.File = xmlSongFile; bool isBass = false; TuningDefinition tuning = null; switch ((ArrangementName)attr.ArrangementType) { case ArrangementName.Lead: case ArrangementName.Rhythm: case ArrangementName.Combo: this.ArrangementType = Sng.ArrangementType.Guitar; tuning = TuningDefinitionRepository.Instance().Select(song.Tuning, GameVersion.RS2014); break; case ArrangementName.Bass: this.ArrangementType = Sng.ArrangementType.Bass; tuning = TuningDefinitionRepository.Instance().SelectForBass(song.Tuning, GameVersion.RS2014); isBass = true; break; case ArrangementName.Vocals: this.ArrangementType = Sng.ArrangementType.Vocal; break; } if (tuning == null) { tuning = new TuningDefinition(); tuning.UIName = tuning.Name = tuning.NameFromStrings(song.Tuning, isBass); tuning.Custom = true; tuning.GameVersion = GameVersion.RS2014; tuning.Tuning = song.Tuning; TuningDefinitionRepository.Instance().Add(tuning, true); } this.Tuning = tuning.UIName; if (attr.CentOffset != null) { this.TuningPitch = attr.CentOffset.Cents2Frequency(); } this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.ToneBase = attr.Tone_Base; this.ToneMultiplayer = attr.Tone_Multiplayer; this.ToneA = attr.Tone_A; this.ToneB = attr.Tone_B; this.ToneC = attr.Tone_C; this.ToneD = attr.Tone_D; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; }
// Load RS1 CDLC into PackageCreator public static DLCPackageData RS1LoadFromFolder(string unpackedDir, Platform targetPlatform, bool convert) { var data = new DLCPackageData(); data.Arrangements = new List<Arrangement>(); data.TonesRS2014 = new List<Tone2014>(); data.Tones = new List<Tone>(); data.GameVersion = (convert ? GameVersion.RS2014 : GameVersion.RS2012); data.SignatureType = PackageMagic.CON; // set default volumes data.Volume = -6.5F; // default maybe too quite data.PreviewVolume = data.Volume; //Load song manifest var songsManifestJson = Directory.GetFiles(unpackedDir, "songs.manifest.json", SearchOption.AllDirectories); if (songsManifestJson.Length < 1) throw new DataException("No songs.manifest.json file found."); if (songsManifestJson.Length > 1) throw new DataException("More than one songs.manifest.json file found."); var attr = new List<Attributes>(); var songsManifest = Manifest.Manifest.LoadFromFile(songsManifestJson[0]).Entries.ToArray(); for (int smIndex = 0; smIndex < songsManifest.Count(); smIndex++) { var smData = songsManifest[smIndex].Value.ToArray()[0].Value; attr.Add(smData); } if (attr.FirstOrDefault() == null) throw new DataException("songs.manifest.json file did not parse correctly."); // Fill SongInfo data.SongInfo = new SongInfo(); data.SongInfo.SongDisplayName = attr.FirstOrDefault().SongName; data.SongInfo.SongDisplayNameSort = attr.FirstOrDefault().SongNameSort; data.SongInfo.Album = attr.FirstOrDefault().AlbumName; data.SongInfo.SongYear = (attr.FirstOrDefault().SongYear == 0 ? 2012 : attr.FirstOrDefault().SongYear); data.SongInfo.Artist = attr.FirstOrDefault().ArtistName; data.SongInfo.ArtistSort = attr.FirstOrDefault().ArtistNameSort; data.Name = attr.FirstOrDefault().SongKey; //Load tone manifest, even poorly formed tone_bass.manifest.json var toneManifestJson = Directory.GetFiles(unpackedDir, "*tone*.manifest.json", SearchOption.AllDirectories); if (toneManifestJson.Length < 1) throw new DataException("No tone.manifest.json file found."); // toolkit produces multiple tone.manifest.json files when packing RS1 CDLC files // rather than change toolkit behavior just merge manifest files for now if (toneManifestJson.Length > 1) { var mergeSettings = new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union }; JObject toneObject1 = new JObject(); foreach (var tone in toneManifestJson) { JObject toneObject2 = JObject.Parse(File.ReadAllText(tone)); //(toneObject1.SelectToken("Entries") as JArray).Merge(toneObject2.SelectToken("Entries")); toneObject1.Merge(toneObject2, mergeSettings); } toneManifestJson = new string[1]; toneManifestJson[0] = Path.Combine(unpackedDir, "merged.tone.manifest.json"); string json = JsonConvert.SerializeObject(toneObject1, Formatting.Indented); File.WriteAllText(toneManifestJson[0], json); } var tones2014 = new List<Tone2014>(); var tones = new List<Tone>(); var toneManifest = Manifest.Tone.Manifest.LoadFromFile(toneManifestJson[0]); for (int tmIndex = 0; tmIndex < toneManifest.Entries.Count(); tmIndex++) { var tmData = toneManifest.Entries[tmIndex]; tones.Add(tmData); } data.Tones = tones; // Load AggregateGraph.nt var songDir = Path.Combine(unpackedDir, data.Name); if (targetPlatform.platform == GamePlatform.XBox360) songDir = Path.Combine(unpackedDir, "Root", data.Name); var aggFile = Directory.GetFiles(songDir, "*.nt", SearchOption.TopDirectoryOnly)[0]; var aggGraphData = AggregateGraph.AggregateGraph.ReadFromFile(aggFile); // Load Exports\Songs\*.xblock var xblockDir = Path.Combine(songDir, "Exports\\Songs"); var xblockFile = Directory.GetFiles(xblockDir, "*.xblock", SearchOption.TopDirectoryOnly)[0]; // xblockFile = "D:\\Temp\\Mapping\\songs.xblock"; var songsXblock = XblockX.LoadFromFile(xblockFile); // create project map for cross referencing arrangements with tones var projectMap = AggregateGraph.AggregateGraph.ProjectMap(aggGraphData, songsXblock, toneManifest); // Load xml arrangements var xmlFiles = Directory.GetFiles(unpackedDir, "*.xml", SearchOption.AllDirectories); if (xmlFiles.Length <= 0) throw new DataException("Can not find any XML arrangement files"); foreach (var xmlFile in xmlFiles) { if (xmlFile.ToLower().Contains("metadata")) // skip DeadFox file continue; // some poorly formed RS1 CDLC use just "vocal" if (xmlFile.ToLower().Contains("vocal")) { // Add Vocal Arrangement data.Arrangements.Add(new Arrangement { Name = ArrangementName.Vocals, ArrangementType = ArrangementType.Vocal, ScrollSpeed = 20, SongXml = new SongXML { File = xmlFile }, SongFile = new SongFile { File = "" }, CustomFont = false }); } else { var attr2014 = new Attributes2014(); var rsSong = new Song(); var rsSong2014 = new Song2014(); // optimized tone matching effort using project mapping algo var result = projectMap.First(m => String.Equals(Path.GetFileName(m.SongXmlPath), Path.GetFileName(xmlFile), StringComparison.CurrentCultureIgnoreCase)); if (result.Tones.Count != 1) throw new DataException("Invalid RS1 CDLC Tones Data"); var arrangement = attr.First(s => s.SongXml.ToLower().Contains(result.LLID)); var tone = tones.First(t => t.Key == result.Tones[0]); using (var obj1 = new Rs1Converter()) { rsSong = obj1.XmlToSong(xmlFile); data.SongInfo.AverageTempo = (int)obj1.AverageBPM(rsSong); } if (arrangement.Tuning == "E Standard") rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; else if (arrangement.Tuning == "DropD") rsSong.Tuning = new TuningStrings { String0 = -2, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; else if (arrangement.Tuning == "OpenG") rsSong.Tuning = new TuningStrings { String0 = -2, String1 = -2, String2 = 0, String3 = 0, String4 = 0, String5 = -2 }; else if (arrangement.Tuning == "EFlat") rsSong.Tuning = new TuningStrings { String0 = -1, String1 = -1, String2 = -1, String3 = -1, String4 = -1, String5 = -1 }; else // default to standard tuning { arrangement.Tuning = "E Standard"; rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; } // save/write the changes to xml file using (var obj1 = new Rs1Converter()) obj1.SongToXml(rsSong, xmlFile, true); if (convert) using (var obj1 = new Rs1Converter()) tones2014.Add(obj1.ToneToTone2014(tone, rsSong)); // load attr2014 with RS1 mapped values for use by Arrangement() attr2014.Tone_Base = tone.Name; attr2014.ArrangementName = arrangement.ArrangementName; attr2014.CentOffset = 0; attr2014.DynamicVisualDensity = new List<float>() { 2 }; attr2014.SongPartition = arrangement.SongPartition; attr2014.PersistentID = IdGenerator.Guid().ToString(); attr2014.MasterID_RDV = RandomGenerator.NextInt(); attr2014.ArrangementProperties = new SongArrangementProperties2014(); // processing order is important - CAREFUL // RouteMask None = 0, Lead = 1, Rhythm = 2, Any = 3, Bass = 4 // XML file names are usually meaningless to arrangement determination if (arrangement.ArrangementName.ToLower().Contains("lead") || rsSong.Arrangement.ToLower().Contains("lead")) { attr2014.ArrangementName = "Lead"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Lead; attr2014.ArrangementProperties.PathLead = 1; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("rhythm") || rsSong.Arrangement.ToLower().Contains("rhythm")) // || rsSong.Arrangement.ToLower().Contains("guitar")) { attr2014.ArrangementName = "Rhythm"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Rhythm; attr2014.ArrangementProperties.PathLead = 0; attr2014.ArrangementProperties.PathRhythm = 1; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("combo") || rsSong.Arrangement.ToLower().Contains("combo")) { attr2014.ArrangementName = "Combo"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = arrangement.EffectChainName.ToLower().Contains("lead") ? (int)RouteMask.Lead : (int)RouteMask.Rhythm; attr2014.ArrangementProperties.PathLead = arrangement.EffectChainName.ToLower().Contains("lead") ? 1 : 0; attr2014.ArrangementProperties.PathRhythm = arrangement.EffectChainName.ToLower().Contains("lead") ? 0 : 1; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("bass") || rsSong.Arrangement.ToLower().Contains("bass")) { attr2014.ArrangementName = "Bass"; attr2014.ArrangementType = (int)ArrangementType.Bass; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Bass; attr2014.ArrangementProperties.PathLead = 0; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 1; } else { // default to Lead arrangment attr2014.ArrangementName = "Lead"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Lead; attr2014.ArrangementProperties.PathLead = 1; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 0; Console.WriteLine("RS1->RS2 CDLC Conversion defaulted to 'Lead' arrangment"); } if (convert) // RS1 -> RS2 magic { using (var obj1 = new Rs1Converter()) rsSong2014 = obj1.SongToSong2014(rsSong); // update ArrangementProperties rsSong2014.ArrangementProperties.RouteMask = attr2014.ArrangementProperties.RouteMask; rsSong2014.ArrangementProperties.PathLead = attr2014.ArrangementProperties.PathLead; rsSong2014.ArrangementProperties.PathRhythm = attr2014.ArrangementProperties.PathRhythm; rsSong2014.ArrangementProperties.PathBass = attr2014.ArrangementProperties.PathBass; rsSong2014.ArrangementProperties.StandardTuning = (arrangement.Tuning == "E Standard" ? 1 : 0); // <note time="58.366" linkNext="0" accent="0" bend="0" fret="7" hammerOn="0" harmonic="0" hopo="0" ignore="0" leftHand="-1" mute="0" palmMute="0" pluck="-1" pullOff="0" slap="-1" slideTo="-1" string="3" sustain="0.108" tremolo="0" harmonicPinch="0" pickDirection="0" rightHand="-1" slideUnpitchTo="-1" tap="0" vibrato="0" /> if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Bend != 0))) rsSong2014.ArrangementProperties.Bends = 1; if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Hopo != 0))) rsSong2014.ArrangementProperties.Hopo = 1; if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.SlideTo != -1))) rsSong2014.ArrangementProperties.Slides = 1; if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Sustain > 0))) rsSong2014.ArrangementProperties.Sustain = 1; // fixing times that are off var lastEbeatsTime = rsSong2014.Ebeats[rsSong2014.Ebeats.Length - 1].Time; var lastPhraseIterationsTime = rsSong2014.PhraseIterations[rsSong2014.PhraseIterations.Length - 1].Time; // tested ... not source of in game hangs // confirm last PhraseIterations time is less than last Ebeats time if (lastPhraseIterationsTime > lastEbeatsTime) { rsSong2014.PhraseIterations[rsSong2014.PhraseIterations.Length - 1].Time = lastEbeatsTime; rsSong2014.Sections[rsSong2014.Sections.Length - 1].StartTime = lastEbeatsTime; } // tested ... not source of in game hangs // confirm SongLength at least equals last Ebeats time if (rsSong2014.SongLength < lastEbeatsTime) rsSong2014.SongLength = lastEbeatsTime; using (var obj2 = new Rs2014Converter()) obj2.Song2014ToXml(rsSong2014, xmlFile, true); } // Adding Song Arrangement try { data.Arrangements.Add(new Arrangement(attr2014, xmlFile)); } catch (Exception ex) { // mainly for the benifit of convert2012 CLI users Console.WriteLine(@"This CDLC could not be auto converted." + Environment.NewLine + "You can still try manually adding the arrangements and assests." + Environment.NewLine + ex.Message); } } } if (convert) { // get rid of duplicate tone names tones2014 = tones2014.Where(p => p.Name != null) .GroupBy(p => p.Name).Select(g => g.First()).ToList(); data.TonesRS2014 = tones2014; } //Get Album Artwork DDS Files var artFiles = Directory.GetFiles(unpackedDir, "*.dds", SearchOption.AllDirectories); if (artFiles.Length < 1) throw new DataException("No Album Artwork file found."); if (artFiles.Length > 1) throw new DataException("More than one Album Artwork file found."); var targetArtFiles = new List<DDSConvertedFile>(); data.AlbumArtPath = artFiles[0]; targetArtFiles.Add(new DDSConvertedFile() { sizeX = 256, sizeY = 256, sourceFile = artFiles[0], destinationFile = artFiles[0].CopyToTempFile(".dds") }); data.ArtFiles = targetArtFiles; //Audio files var targetAudioFiles = new List<string>(); var audioFiles = Directory.GetFiles(unpackedDir, "*.ogg", SearchOption.AllDirectories); if (audioFiles.Length < 1) throw new DataException("No Audio file found."); if (audioFiles.Length > 2) throw new DataException("Too many Audio files found."); int i; for (i = 0; i < audioFiles.Length; i++) { if (convert && audioFiles[i].Contains("_fixed.ogg")) // use it break; if (!convert && !audioFiles[i].Contains("_fixed.ogg")) break; } // FIXME: platform specific decode is broken var sourcePlatform = unpackedDir.GetPlatform(); if (targetPlatform.IsConsole != (sourcePlatform = audioFiles[i].GetAudioPlatform()).IsConsole) { var newFile = Path.Combine(Path.GetDirectoryName(audioFiles[i]), String.Format("{0}_cap.ogg", Path.GetFileNameWithoutExtension(audioFiles[i]))); OggFile.ConvertAudioPlatform(audioFiles[i], newFile); audioFiles[i] = newFile; } targetAudioFiles.Add(audioFiles[i]); if (!targetAudioFiles.Any()) throw new DataException("Audio file not found."); var a = new FileInfo(audioFiles[i]); data.OggPath = a.FullName; //AppID if (!sourcePlatform.IsConsole) { if (!convert) { var appidFile = Directory.GetFiles(unpackedDir, "*APP_ID*", SearchOption.AllDirectories); if (appidFile.Length > 0) data.AppId = File.ReadAllText(appidFile[0]); } else data.AppId = "248750"; } try {//TODO: validate that rs1 songs have no this file //Package version var versionFile = Directory.GetFiles(unpackedDir, "toolkit.version", SearchOption.AllDirectories); if (versionFile.Length > 0) data.PackageVersion = GeneralExtensions.ReadPackageVersion(versionFile[0]); else data.PackageVersion = "1"; } catch {} if (convert) data.Tones = null; return data; }
// Load RS1 CDLC into PackageCreator public static DLCPackageData RS1LoadFromFolder(string unpackedDir, Platform targetPlatform, bool convert) { var data = new DLCPackageData(); data.Arrangements = new List <Arrangement>(); data.TonesRS2014 = new List <Tone2014>(); data.Tones = new List <Tone>(); data.GameVersion = (convert ? GameVersion.RS2014 : GameVersion.RS2012); data.SignatureType = PackageMagic.CON; // set default volumes data.Volume = -6.5F; // default maybe too quite data.PreviewVolume = data.Volume; //Load song manifest var songsManifestJson = Directory.GetFiles(unpackedDir, "songs.manifest.json", SearchOption.AllDirectories); if (songsManifestJson.Length < 1) { throw new DataException("No songs.manifest.json file found."); } if (songsManifestJson.Length > 1) { throw new DataException("More than one songs.manifest.json file found."); } var attr = new List <Attributes>(); var songsManifest = Manifest.Manifest.LoadFromFile(songsManifestJson[0]).Entries.ToArray(); for (int smIndex = 0; smIndex < songsManifest.Count(); smIndex++) { var smData = songsManifest[smIndex].Value.ToArray()[0].Value; attr.Add(smData); } if (attr.FirstOrDefault() == null) { throw new DataException("songs.manifest.json file did not parse correctly."); } // Fill SongInfo data.SongInfo = new SongInfo(); data.SongInfo.SongDisplayName = attr.FirstOrDefault().SongName; data.SongInfo.SongDisplayNameSort = attr.FirstOrDefault().SongNameSort; data.SongInfo.Album = attr.FirstOrDefault().AlbumName; data.SongInfo.SongYear = (attr.FirstOrDefault().SongYear == 0 ? 2012 : attr.FirstOrDefault().SongYear); data.SongInfo.Artist = attr.FirstOrDefault().ArtistName; data.SongInfo.ArtistSort = attr.FirstOrDefault().ArtistNameSort; data.Name = attr.FirstOrDefault().SongKey; //Load tone manifest, even poorly formed tone_bass.manifest.json var toneManifestJson = Directory.GetFiles(unpackedDir, "*tone*.manifest.json", SearchOption.AllDirectories); if (toneManifestJson.Length < 1) { throw new DataException("No tone.manifest.json file found."); } // toolkit produces multiple tone.manifest.json files when packing RS1 CDLC files // rather than change toolkit behavior just merge manifest files for now if (toneManifestJson.Length > 1) { var mergeSettings = new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union }; JObject toneObject1 = new JObject(); foreach (var tone in toneManifestJson) { JObject toneObject2 = JObject.Parse(File.ReadAllText(tone)); //(toneObject1.SelectToken("Entries") as JArray).Merge(toneObject2.SelectToken("Entries")); toneObject1.Merge(toneObject2, mergeSettings); } toneManifestJson = new string[1]; toneManifestJson[0] = Path.Combine(unpackedDir, "merged.tone.manifest.json"); string json = JsonConvert.SerializeObject(toneObject1, Formatting.Indented); File.WriteAllText(toneManifestJson[0], json); } var tones2014 = new List <Tone2014>(); var tones = new List <Tone>(); var toneManifest = Manifest.Tone.Manifest.LoadFromFile(toneManifestJson[0]); for (int tmIndex = 0; tmIndex < toneManifest.Entries.Count(); tmIndex++) { var tmData = toneManifest.Entries[tmIndex]; tones.Add(tmData); } data.Tones = tones; // Load AggregateGraph.nt var songDir = Path.Combine(unpackedDir, data.Name); if (targetPlatform.platform == GamePlatform.XBox360) { songDir = Path.Combine(unpackedDir, "Root", data.Name); } var aggFile = Directory.GetFiles(songDir, "*.nt", SearchOption.TopDirectoryOnly)[0]; var aggGraphData = AggregateGraph.AggregateGraph.ReadFromFile(aggFile); // Load Exports\Songs\*.xblock var xblockDir = Path.Combine(songDir, "Exports\\Songs"); var xblockFile = Directory.GetFiles(xblockDir, "*.xblock", SearchOption.TopDirectoryOnly)[0]; // xblockFile = "D:\\Temp\\Mapping\\songs.xblock"; var songsXblock = XblockX.LoadFromFile(xblockFile); // create project map for cross referencing arrangements with tones var projectMap = AggregateGraph.AggregateGraph.ProjectMap(aggGraphData, songsXblock, toneManifest); // Load xml arrangements var xmlFiles = Directory.GetFiles(unpackedDir, "*.xml", SearchOption.AllDirectories); if (xmlFiles.Length <= 0) { throw new DataException("Can not find any XML arrangement files"); } foreach (var xmlFile in xmlFiles) { if (xmlFile.ToLower().Contains("metadata")) { continue; } // some poorly formed RS1 CDLC use just "vocal" if (xmlFile.ToLower().Contains("vocal")) { // Add Vocal Arrangement data.Arrangements.Add(new Arrangement { Name = ArrangementName.Vocals, ArrangementType = ArrangementType.Vocal, ScrollSpeed = 20, SongXml = new SongXML { File = xmlFile }, SongFile = new SongFile { File = "" }, CustomFont = false }); } else { var attr2014 = new Attributes2014(); var rsSong = new Song(); var rsSong2014 = new Song2014(); // optimized tone matching effort using project mapping algo var result = projectMap.First(m => String.Equals(Path.GetFileName(m.SongXmlPath), Path.GetFileName(xmlFile), StringComparison.CurrentCultureIgnoreCase)); if (result.Tones.Count != 1) { throw new DataException("Invalid RS1 CDLC Tones Data"); } var arrangement = attr.First(s => s.SongXml.ToLower().Contains(result.LLID));//FIXME: Sequence contains no matching element issue var tone = tones.First(t => t.Key == result.Tones[0]); using (var obj1 = new Rs1Converter()) { rsSong = obj1.XmlToSong(xmlFile); data.SongInfo.AverageTempo = (int)obj1.AverageBPM(rsSong); } if (arrangement.Tuning == "E Standard") { rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } } ; else if (arrangement.Tuning == "DropD") { rsSong.Tuning = new TuningStrings { String0 = -2, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } } ; else if (arrangement.Tuning == "OpenG") { rsSong.Tuning = new TuningStrings { String0 = -2, String1 = -2, String2 = 0, String3 = 0, String4 = 0, String5 = -2 } } ; else if (arrangement.Tuning == "EFlat") { rsSong.Tuning = new TuningStrings { String0 = -1, String1 = -1, String2 = -1, String3 = -1, String4 = -1, String5 = -1 } } ; else // default to standard tuning { arrangement.Tuning = "E Standard"; rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; } // save/write the changes to xml file using (var obj1 = new Rs1Converter()) obj1.SongToXml(rsSong, xmlFile, true); if (convert) { using (var obj1 = new Rs1Converter()) tones2014.Add(obj1.ToneToTone2014(tone, rsSong)); } // load attr2014 with RS1 mapped values for use by Arrangement() attr2014.Tone_Base = tone.Name; attr2014.ArrangementName = arrangement.ArrangementName; attr2014.CentOffset = 0; attr2014.DynamicVisualDensity = new List <float>() { 2 }; attr2014.SongPartition = arrangement.SongPartition; attr2014.PersistentID = IdGenerator.Guid().ToString(); attr2014.MasterID_RDV = RandomGenerator.NextInt(); attr2014.ArrangementProperties = new SongArrangementProperties2014(); // processing order is important - CAREFUL // RouteMask None = 0, Lead = 1, Rhythm = 2, Any = 3, Bass = 4 // XML file names are usually meaningless to arrangement determination if (arrangement.ArrangementName.ToLower().Contains("lead") || rsSong.Arrangement.ToLower().Contains("lead")) { attr2014.ArrangementName = "Lead"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Lead; attr2014.ArrangementProperties.PathLead = 1; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("rhythm") || rsSong.Arrangement.ToLower().Contains("rhythm")) // || rsSong.Arrangement.ToLower().Contains("guitar")) { attr2014.ArrangementName = "Rhythm"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Rhythm; attr2014.ArrangementProperties.PathLead = 0; attr2014.ArrangementProperties.PathRhythm = 1; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("combo") || rsSong.Arrangement.ToLower().Contains("combo")) { attr2014.ArrangementName = "Combo"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = arrangement.EffectChainName.ToLower().Contains("lead") ? (int)RouteMask.Lead : (int)RouteMask.Rhythm; attr2014.ArrangementProperties.PathLead = arrangement.EffectChainName.ToLower().Contains("lead") ? 1 : 0; attr2014.ArrangementProperties.PathRhythm = arrangement.EffectChainName.ToLower().Contains("lead") ? 0 : 1; attr2014.ArrangementProperties.PathBass = 0; } else if (arrangement.ArrangementName.ToLower().Contains("bass") || rsSong.Arrangement.ToLower().Contains("bass")) { attr2014.ArrangementName = "Bass"; attr2014.ArrangementType = (int)ArrangementType.Bass; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Bass; attr2014.ArrangementProperties.PathLead = 0; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 1; } else { // default to Lead arrangement attr2014.ArrangementName = "Lead"; attr2014.ArrangementType = (int)ArrangementType.Guitar; attr2014.ArrangementProperties.RouteMask = (int)RouteMask.Lead; attr2014.ArrangementProperties.PathLead = 1; attr2014.ArrangementProperties.PathRhythm = 0; attr2014.ArrangementProperties.PathBass = 0; Console.WriteLine("RS1->RS2 CDLC Conversion defaulted to 'Lead' arrangement"); } if (convert) // RS1 -> RS2 magic { using (var obj1 = new Rs1Converter()) rsSong2014 = obj1.SongToSong2014(rsSong); // update ArrangementProperties rsSong2014.ArrangementProperties.RouteMask = attr2014.ArrangementProperties.RouteMask; rsSong2014.ArrangementProperties.PathLead = attr2014.ArrangementProperties.PathLead; rsSong2014.ArrangementProperties.PathRhythm = attr2014.ArrangementProperties.PathRhythm; rsSong2014.ArrangementProperties.PathBass = attr2014.ArrangementProperties.PathBass; rsSong2014.ArrangementProperties.StandardTuning = (arrangement.Tuning == "E Standard" ? 1 : 0); // <note time="58.366" linkNext="0" accent="0" bend="0" fret="7" hammerOn="0" harmonic="0" hopo="0" ignore="0" leftHand="-1" mute="0" palmMute="0" pluck="-1" pullOff="0" slap="-1" slideTo="-1" string="3" sustain="0.108" tremolo="0" harmonicPinch="0" pickDirection="0" rightHand="-1" slideUnpitchTo="-1" tap="0" vibrato="0" /> if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Bend != 0))) { rsSong2014.ArrangementProperties.Bends = 1; } if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Hopo != 0))) { rsSong2014.ArrangementProperties.Hopo = 1; } if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.SlideTo != -1))) { rsSong2014.ArrangementProperties.Slides = 1; } if (rsSong2014.Levels.Any(sl => sl.Notes.Any(sln => sln.Sustain > 0))) { rsSong2014.ArrangementProperties.Sustain = 1; } // fixing times that are off var lastEbeatsTime = rsSong2014.Ebeats[rsSong2014.Ebeats.Length - 1].Time; var lastPhraseIterationsTime = rsSong2014.PhraseIterations[rsSong2014.PhraseIterations.Length - 1].Time; // tested ... not source of in game hangs // confirm last PhraseIterations time is less than last Ebeats time if (lastPhraseIterationsTime > lastEbeatsTime) { rsSong2014.PhraseIterations[rsSong2014.PhraseIterations.Length - 1].Time = lastEbeatsTime; rsSong2014.Sections[rsSong2014.Sections.Length - 1].StartTime = lastEbeatsTime; } // tested ... not source of in game hangs // confirm SongLength at least equals last Ebeats time if (rsSong2014.SongLength < lastEbeatsTime) { rsSong2014.SongLength = lastEbeatsTime; } using (var obj2 = new Rs2014Converter()) obj2.Song2014ToXml(rsSong2014, xmlFile, true); } // Adding Song Arrangement try { data.Arrangements.Add(new Arrangement(attr2014, xmlFile)); } catch (Exception ex) { // mainly for the benefit of convert2012 CLI users Console.WriteLine(@"This CDLC could not be auto converted." + Environment.NewLine + "You can still try manually adding the arrangements and assets." + Environment.NewLine + ex.Message); } } } if (convert) { // get rid of duplicate tone names tones2014 = tones2014.Where(p => p.Name != null) .GroupBy(p => p.Name).Select(g => g.First()).ToList(); data.TonesRS2014 = tones2014; } //Get Album Artwork DDS Files var artFiles = Directory.GetFiles(unpackedDir, "*.dds", SearchOption.AllDirectories); if (artFiles.Length < 1) { throw new DataException("No Album Artwork file found."); } if (artFiles.Length > 1) { throw new DataException("More than one Album Artwork file found."); } var targetArtFiles = new List <DDSConvertedFile>(); data.AlbumArtPath = artFiles[0]; targetArtFiles.Add(new DDSConvertedFile() { sizeX = 256, sizeY = 256, sourceFile = artFiles[0], destinationFile = artFiles[0].CopyToTempFile(".dds") }); data.ArtFiles = targetArtFiles; //Audio files var targetAudioFiles = new List <string>(); var audioFiles = Directory.GetFiles(unpackedDir, "*.ogg", SearchOption.AllDirectories); if (audioFiles.Length < 1) { throw new DataException("No Audio file found."); } if (audioFiles.Length > 2) { throw new DataException("Too many Audio files found."); } int i; for (i = 0; i < audioFiles.Length; i++) { if (convert && audioFiles[i].Contains("_fixed.ogg")) // use it { break; } if (!convert && !audioFiles[i].Contains("_fixed.ogg")) { break; } } // FIXME: platform specific decode is broken var sourcePlatform = unpackedDir.GetPlatform(); if (targetPlatform.IsConsole != (sourcePlatform = audioFiles[i].GetAudioPlatform()).IsConsole) { var newFile = Path.Combine(Path.GetDirectoryName(audioFiles[i]), String.Format("{0}_cap.ogg", Path.GetFileNameWithoutExtension(audioFiles[i]))); OggFile.ConvertAudioPlatform(audioFiles[i], newFile); audioFiles[i] = newFile; } targetAudioFiles.Add(audioFiles[i]); if (!targetAudioFiles.Any()) { throw new DataException("Audio file not found."); } var a = new FileInfo(audioFiles[i]); data.OggPath = a.FullName; //AppID if (!sourcePlatform.IsConsole) { if (!convert) { var appidFile = Directory.GetFiles(unpackedDir, "*APP_ID*", SearchOption.AllDirectories); if (appidFile.Length > 0) { data.AppId = File.ReadAllText(appidFile[0]); } } else { data.AppId = "248750"; } } try { // Package Info var versionFile = Directory.EnumerateFiles(unpackedDir, "toolkit.version", SearchOption.AllDirectories).FirstOrDefault(); if (versionFile != null) { var tkInfo = GeneralExtensions.ReadToolkitInfo(versionFile); data.PackageVersion = tkInfo.PackageVersion; data.PackageComment = tkInfo.PackageComment; } else { data.PackageVersion = "1"; data.PackageComment = ""; } } catch { } if (convert) { data.Tones = null; } return(data); }
/// <summary> /// Fill Arrangement 2014 from json and xml. /// </summary> /// <param name="attr"></param> /// <param name="xmlSongFile"></param> public Arrangement(Attributes2014 attr, string xmlSongFile) { var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile { File = "" }; this.SongXml = new SongXML { File = xmlSongFile }; //Properties Debug.Assert(attr.ArrangementType != null, "Missing information from manifest (ArrangementType)"); SetArrType(attr.ArrangementType); this.ArrangementPropeties = attr.ArrangementProperties; this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; //Filter out showlights\vocals if (ArrangementType != ArrangementType.Guitar && ArrangementType != ArrangementType.Bass) { return; } //Tuning DetectTuning(song); this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) { this.TuningPitch = attr.CentOffset.Cents2Frequency(); } // save xml comments this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); //Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) { throw new DataException("RS2012 CDLC has extraneous tone data."); } } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) { continue; } // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangement file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) { this.ToneBase = song.ToneBase = attr.Tone_Base; } if (attr.Tone_A != null && jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) { this.ToneA = song.ToneA = attr.Tone_A; } if (attr.Tone_B != null && jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (attr.Tone_C != null && jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (attr.Tone_D != null && jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) { foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") { xmlTone.Name = attr.Tone_A; } if (xmlTone.Name == "ToneB") { xmlTone.Name = attr.Tone_B; } if (xmlTone.Name == "ToneC") { xmlTone.Name = attr.Tone_C; } if (xmlTone.Name == "ToneD") { xmlTone.Name = attr.Tone_D; } if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().EndsWith(xmlTone.Name.ToLower())) //todo: SAMENAME tone fix? { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } } if (song.Tones == null && toneId > 0) { throw new InvalidDataException("Custom tones were not set properly in EOF" + Environment.NewLine + "Please re-author XML arrangement in EOF and fix custom tone consistency."); } } // write changes to xml arrangement (w/o comments) using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream, true); // write comments back to xml now so they are available for debugging (used for Guitar and Bass) Song2014.WriteXmlComments(xmlSongFile, XmlComments, writeNewVers: false); } }
/// <summary> /// Unpack the specified File, returns unpacked dir. /// </summary> /// <param name="sourceFileName">Source file path.</param> /// <param name="savePath">Save path.</param> /// <param name="decodeAudio">If set to <c>true</c> decode audio.</param> /// <param name="extractSongXml">If set to <c>true</c> extract song xml from sng.</param> /// <param name="overwriteSongXml">If set to <c>true</c> overwrite existing song xml with produced.</param> /// <param name="predefinedPlatform">Predefined source platform.</param> public static string Unpack(string sourceFileName, string savePath, bool decodeAudio = false, bool extractSongXml = false, bool overwriteSongXml = true, Platform predefinedPlatform = null) { Platform platform = sourceFileName.GetPlatform(); if (predefinedPlatform != null && predefinedPlatform.platform != GamePlatform.None && predefinedPlatform.version != GameVersion.None) { platform = predefinedPlatform; } var fnameWithoutExt = Path.GetFileNameWithoutExtension(sourceFileName); var unpackedDir = Path.Combine(savePath, String.Format("{0}_{1}", fnameWithoutExt, platform.platform)); if (Directory.Exists(unpackedDir)) { DirectoryExtension.SafeDelete(unpackedDir); } var useCryptography = platform.version == GameVersion.RS2012; // Cryptography way is used only for PC in Rocksmith 1 switch (platform.platform) { case GamePlatform.Pc: case GamePlatform.Mac: if (platform.version == GameVersion.RS2014) { using (var inputStream = File.OpenRead(sourceFileName)) ExtractPSARC(sourceFileName, savePath, inputStream, platform); } else { using (var inputFileStream = File.OpenRead(sourceFileName)) using (var inputStream = new MemoryStream()) { if (useCryptography) { RijndaelEncryptor.DecryptFile(inputFileStream, inputStream, RijndaelEncryptor.DLCKey); } else { inputFileStream.CopyTo(inputStream); } ExtractPSARC(sourceFileName, savePath, inputStream, platform); } } break; case GamePlatform.XBox360: UnpackXBox360Package(sourceFileName, savePath, platform); break; case GamePlatform.PS3: UnpackPS3Package(sourceFileName, savePath, platform); break; case GamePlatform.None: throw new InvalidOperationException("Platform not found :("); } if (platform.platform == GamePlatform.PS3) { fnameWithoutExt = fnameWithoutExt.Substring(0, fnameWithoutExt.LastIndexOf(".")); } // DECODE AUDIO if (decodeAudio) { var audioFiles = Directory.EnumerateFiles(unpackedDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".ogg") || s.EndsWith(".wem")); foreach (var file in audioFiles) { var outputAudioFileName = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_fixed{1}", Path.GetFileNameWithoutExtension(file), ".ogg")); OggFile.Revorb(file, outputAudioFileName, Path.GetDirectoryName(Application.ExecutablePath), Path.GetExtension(file).GetWwiseVersion()); } } // EXTRACT XML FROM SNG if (extractSongXml && platform.version == GameVersion.RS2014) { var sngFiles = Directory.EnumerateFiles(unpackedDir, "*.sng", SearchOption.AllDirectories); foreach (var sngFile in sngFiles) { var xmlOutput = Path.Combine(Path.GetDirectoryName(sngFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(sngFile))); xmlOutput = xmlOutput.Replace(String.Format("bin{0}{1}", Path.DirectorySeparatorChar, platform.GetPathName()[1].ToLower()), "arr"); if (File.Exists(xmlOutput) && !overwriteSongXml) { continue; } var arrType = ArrangementType.Guitar; if (Path.GetFileName(xmlOutput).ToLower().Contains("vocal")) { arrType = ArrangementType.Vocal; } Attributes2014 att = null; if (arrType != ArrangementType.Vocal) { var jsonFiles = Directory.EnumerateFiles(unpackedDir, String.Format("{0}.json", Path.GetFileNameWithoutExtension(sngFile)), SearchOption.AllDirectories).FirstOrDefault(); if (jsonFiles.Any() && !String.IsNullOrEmpty(jsonFiles)) { att = Manifest2014 <Attributes2014> .LoadFromFile(jsonFiles).Entries.ToArray()[0].Value.ToArray()[0].Value; } } var sngContent = Sng2014File.LoadFromFile(sngFile, platform); using (var outputStream = new FileStream(xmlOutput, FileMode.Create, FileAccess.ReadWrite)) { dynamic xmlContent = null; if (arrType == ArrangementType.Vocal) { xmlContent = new Vocals(sngContent); } else { xmlContent = new Song2014(sngContent, att); } xmlContent.Serialize(outputStream); } } } return(unpackedDir); }
private int ApplyPackageDD(string file, string remSUS, string rampPath, out string consoleOutputPkg) { int singleResult = -1; bool exitedByError = false; consoleOutputPkg = String.Empty; var tmpDir = Path.GetTempPath(); var platform = file.GetPlatform(); var unpackedDir = Packer.Unpack(file, tmpDir, false, true, false); var xmlFiles = Directory.GetFiles(unpackedDir, "*.xml", SearchOption.AllDirectories); foreach (var xml in xmlFiles) { if (Path.GetFileNameWithoutExtension(xml).ToLower().Contains("vocal")) { continue; } if (Path.GetFileNameWithoutExtension(xml).ToLower().Contains("showlight")) { continue; } singleResult = ApplyDD(xml, remSUS, rampPath, out consoleOutputPkg, true, false); // UPDATE MANIFEST (RS2014) for update if (platform.version == RocksmithToolkitLib.GameVersion.RS2014) { var json = Directory.GetFiles(unpackedDir, String.Format("*{0}.json", Path.GetFileNameWithoutExtension(xml)), SearchOption.AllDirectories); if (json.Length > 0) { Attributes2014 attr = Manifest2014 <Attributes2014> .LoadFromFile(json[0]).Entries.ToArray()[0].Value.ToArray()[0].Value; Song2014 xmlContent = Song2014.LoadFromFile(xml); var manifestFunctions = new ManifestFunctions(platform.version); attr.PhraseIterations = new List <PhraseIteration>(); manifestFunctions.GeneratePhraseIterationsData(attr, xmlContent, platform.version); attr.Phrases = new List <Phrase>(); manifestFunctions.GeneratePhraseData(attr, xmlContent); attr.Sections = new List <Section>(); manifestFunctions.GenerateSectionData(attr, xmlContent); attr.MaxPhraseDifficulty = manifestFunctions.GetMaxDifficulty(xmlContent); var manifest = new Manifest2014 <Attributes2014>(); var attributeDictionary = new Dictionary <string, Attributes2014> { { "Attributes", attr } }; manifest.Entries.Add(attr.PersistentID, attributeDictionary); manifest.SaveToFile(json[0]); } } if (singleResult == 1) { exitedByError = true; break; } else if (singleResult == 2) { consoleOutputPkg = String.Format("Arrangement file '{0}' => {1}", Path.GetFileNameWithoutExtension(xml), consoleOutputPkg); } } if (!exitedByError) { var newName = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_{1}{2}", Path.GetFileNameWithoutExtension(file).StripPlatformEndName().GetValidName(false).Replace("_DD", "").Replace("_NDD", ""), isNDD ? "NDD" : "DD", platform.GetPathName()[2])); Packer.Pack(unpackedDir, newName, true, platform); DirectoryExtension.SafeDelete(unpackedDir); } return(singleResult); }
public void GenerateTechniques(Attributes2014 attribute, Song2014 song) { // results from this method do not match ODLC but are workable // //"Techniques" : { // "DiffLevelID" : {//used to display which techs are set at current lvl. // "SectionNumber" : [// > 0 // TechID, //required base tech for extended tech(?) // TechID // ] // }, // } if (song.Sections == null) { return; } attribute.Techniques = new Dictionary <string, Dictionary <string, List <int> > >(); for (int difficulty = 0; difficulty < song.Levels.Length; difficulty++) { var notes = song.Levels[difficulty].Notes; var sectionId = new Dictionary <string, List <int> >(); var techId = new List <int>(); for (int section = 0; section < song.Sections.Length; section++) { var sectionNumber = song.Sections[section].Number; var starTime = song.Sections[section].StartTime; var endTime = song.Sections[Math.Min(section + 1, song.Sections.Length - 1)].StartTime; // iterate through notes in section in the difficulty level foreach (var note in notes) { if (note.Time >= starTime && note.Time < endTime) //in range { var noteTech = getNoteTech(note); // needs tweaking techId.AddRange(noteTech); } } if (techId.Count > 0) { // TODO: needs more tweaking // techId.Add(35); // try adding dumby data for now List <int> distinctTechIds = techId.Distinct().OrderBy(x => x).ToList(); // sometimes sectionNumbers are not unique so duplicate key throws an error if not checked if (sectionId.ContainsKey(sectionNumber.ToString())) { // get the current values and make sure all combined values are distinct var techIdValue = sectionId[sectionNumber.ToString()]; techIdValue.AddRange(distinctTechIds); distinctTechIds = techIdValue.Distinct().OrderBy(x => x).ToList(); sectionId.Remove(sectionNumber.ToString()); } sectionId.Add(sectionNumber.ToString(), distinctTechIds); } techId = new List <int>(); } /* * "5": { * "1": [ * 13, * 35 <- missing * ], */ if (sectionId.Keys.Count > 0) { attribute.Techniques.Add(difficulty.ToString(), sectionId); } } }
public static DLCPackageData LoadFromFile(string unpackedDir, Platform targetPlatform) { //Load files var jsonFiles = Directory.GetFiles(unpackedDir, "*.json", SearchOption.AllDirectories); var data = new DLCPackageData(); data.GameVersion = GameVersion.RS2014; data.SignatureType = PackageMagic.CON; //Get Arrangements / Tones data.Arrangements = new List <Arrangement>(); data.TonesRS2014 = new List <Tone2014>(); foreach (var json in jsonFiles) { Attributes2014 attr = Manifest2014 <Attributes2014> .LoadFromFile(json).Entries.ToArray()[0].Value.ToArray()[0].Value; var xmlName = attr.SongXml.Split(':')[3]; var xmlFile = Directory.GetFiles(unpackedDir, xmlName + ".xml", SearchOption.AllDirectories)[0]; if (attr.Phrases != null) { if (data.SongInfo == null) { // Fill Package Data data.Name = attr.DLCKey; data.Volume = attr.SongVolume; data.PreviewVolume = (attr.PreviewVolume != null) ? (float)attr.PreviewVolume : data.Volume; // Fill SongInfo data.SongInfo = new SongInfo(); data.SongInfo.SongDisplayName = attr.SongName; data.SongInfo.SongDisplayNameSort = attr.SongNameSort; data.SongInfo.Album = attr.AlbumName; data.SongInfo.SongYear = attr.SongYear ?? 0; data.SongInfo.Artist = attr.ArtistName; data.SongInfo.ArtistSort = attr.ArtistNameSort; data.SongInfo.AverageTempo = (int)attr.SongAverageTempo; } // Adding Tones foreach (var jsonTone in attr.Tones) { if (jsonTone == null) { continue; } if (!data.TonesRS2014.OfType <Tone2014>().Any(t => t.Key == jsonTone.Key)) { data.TonesRS2014.Add(jsonTone); } } // Adding Arrangement data.Arrangements.Add(new Arrangement(attr, xmlFile)); } else { var voc = new Arrangement(); voc.Name = ArrangementName.Vocals; voc.ArrangementType = ArrangementType.Vocal; voc.SongXml = new SongXML { File = xmlFile }; voc.SongFile = new SongFile { File = "" }; voc.Sng2014 = Sng2014HSL.Sng2014File.ConvertXML(xmlFile, ArrangementType.Vocal); voc.ScrollSpeed = 20; // Adding Arrangement data.Arrangements.Add(voc); } } //Get Files var ddsFiles = Directory.GetFiles(unpackedDir, "*_256.dds", SearchOption.AllDirectories); if (ddsFiles.Length > 0) { data.AlbumArtPath = ddsFiles[0]; } var sourceAudioFiles = Directory.GetFiles(unpackedDir, "*.wem", SearchOption.AllDirectories); var targetAudioFiles = new List <string>(); foreach (var file in sourceAudioFiles) { var newFile = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_fixed{1}", Path.GetFileNameWithoutExtension(file), Path.GetExtension(file))); if (targetPlatform.IsConsole != file.GetAudioPlatform().IsConsole) { OggFile.ConvertAudioPlatform(file, newFile); targetAudioFiles.Add(newFile); } else { targetAudioFiles.Add(file); } } if (targetAudioFiles.Count() <= 0) { throw new InvalidDataException("Audio files not found."); } string audioPath = null, audioPreviewPath = null; FileInfo a = new FileInfo(targetAudioFiles[0]); FileInfo b = null; if (targetAudioFiles.Count() == 2) { b = new FileInfo(targetAudioFiles[1]); if (a.Length > b.Length) { audioPath = a.FullName; audioPreviewPath = b.FullName; } else { audioPath = b.FullName; audioPreviewPath = a.FullName; } } else { audioPath = a.FullName; } data.OggPath = audioPath; //Make Audio preview with expected name when rebuild if (!String.IsNullOrEmpty(audioPreviewPath)) { var newPreviewFileName = Path.Combine(Path.GetDirectoryName(audioPath), String.Format("{0}_preview{1}", Path.GetFileNameWithoutExtension(audioPath), Path.GetExtension(audioPath))); File.Move(audioPreviewPath, newPreviewFileName); data.OggPreviewPath = newPreviewFileName; } var appidFile = Directory.GetFiles(unpackedDir, "*.appid", SearchOption.AllDirectories); if (appidFile.Length > 0) { data.AppId = File.ReadAllText(appidFile[0]); } return(data); }
/// <summary> /// Fill Arrangement 2014 from json and xml. /// </summary> /// <param name="attr"></param> /// <param name="xmlSongFile"></param> /// <param name="fixMultiTone">If set to <c>true</c> fix low bass tuning </param> /// <param name="fixLowBass">If set to <c>true</c> fix multitone exceptions </param> public Arrangement(Attributes2014 attr, string xmlSongFile, bool fixMultiTone = false, bool fixLowBass = false) { var isDirty = false; var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile { File = "" }; this.SongXml = new SongXML { File = xmlSongFile }; //Properties Debug.Assert(attr.ArrangementType != null, "Missing information from manifest (ArrangementType)"); SetArrType(attr.ArrangementType); this.ArrangementPropeties = attr.ArrangementProperties; this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; // Save xml comments this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); // Filter out showlights\vocals if (ArrangementType != ArrangementType.Guitar && ArrangementType != ArrangementType.Bass) { return; } // Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) { throw new DataException("RS2012 CDLC has extraneous tone data."); } } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) { continue; } // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangement file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) { this.ToneBase = song.ToneBase = attr.Tone_Base; } if (attr.Tone_A != null && jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) { this.ToneA = song.ToneA = attr.Tone_A; } if (attr.Tone_B != null && jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (attr.Tone_C != null && jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (attr.Tone_D != null && jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) { foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") { xmlTone.Name = attr.Tone_A; } if (xmlTone.Name == "ToneB") { xmlTone.Name = attr.Tone_B; } if (xmlTone.Name == "ToneC") { xmlTone.Name = attr.Tone_C; } if (xmlTone.Name == "ToneD") { xmlTone.Name = attr.Tone_D; } if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().EndsWith(xmlTone.Name.ToLower())) //todo: SAMENAME tone fix? { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } } // song.Tones => id, name, time to apply tone is missing when song.Tones == null if (song.Tones == null && toneId > 0) { // convert the corrupt multitone to a single tone instead of throwing exception if (fixMultiTone) { song.Tones = new SongTone2014[0]; // => song.Tones.Length == 0 isDirty = true; } else { throw new InvalidDataException("Tone data is missing in CDLC and multitones will not change properly in game." + Environment.NewLine + "Please re-author XML arrangements in EOF and repair multitones name and time changes."); } } } // convert corrupt multitone to single tone and/or cleanup/repair old toolkit single tone // ToneA in single tone ODLC is null/empty if ((song.Tones == null || song.Tones.Length == 0) && !String.IsNullOrEmpty(song.ToneA)) { song.ToneA = song.ToneB = song.ToneC = String.Empty; song.ToneBase = attr.Tone_Base; this.ToneBase = attr.Tone_Base; this.ToneA = this.ToneB = this.ToneC = String.Empty; isDirty = true; } // set to standard tuning if no tuning exists if (song.Tuning == null) { song.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; isDirty = true; } this.TuningStrings = song.Tuning; // NOTE: any serializing coverts abridged xml to standard xml arrangement // so only serialize if necessary to fix errors if (isDirty) { using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream, true); // write comments back to xml now so they are available for debugging (used for Guitar and Bass) Song2014.WriteXmlComments(xmlSongFile, XmlComments, writeNewVers: false); } // do a quick check/repair of low bass tuning, only for RS2014 bass arrangements if (fixLowBass && song.Version == "7" && this.ArrangementType == ArrangementType.Bass) { if (attr.Tuning.String0 < -4 && attr.CentOffset != -1200.0) { if (TuningFrequency.ApplyBassFix(this, fixLowBass)) { attr.CentOffset = -1200.0; // Force 220Hz song.Tuning = Song2014.LoadFromFile(xmlSongFile).Tuning; } } } } // Set Final Tuning DetectTuning(song); this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) { this.TuningPitch = attr.CentOffset.Cents2Frequency(); } }
private static void GenerateRS2014SongPsarc(Stream output, DLCPackageData info, Platform platform, int pnum = -1) { // TODO: Benchmark processes and optimize speed dlcName = info.Name.ToLower(); packPsarc = new PSARC.PSARC(); // Stream objects Stream soundStream = null, soundPreviewStream = null, rsenumerableRootStream = null, rsenumerableSongStream = null; try { // ALBUM ART var ddsfiles = info.ArtFiles; if (ddsfiles == null) { string albumArtPath; if (File.Exists(info.AlbumArtPath)) { albumArtPath = info.AlbumArtPath; } else { using (var albumArtStream = new MemoryStream(Resources.albumart2014_256)) { albumArtPath = GeneralExtensions.GetTempFileName(".dds"); albumArtStream.WriteFile(albumArtPath); TMPFILES_ART.Add(albumArtPath); } } ddsfiles = new List<DDSConvertedFile>(); ddsfiles.Add(new DDSConvertedFile() { sizeX = 64, sizeY = 64, sourceFile = albumArtPath, destinationFile = GeneralExtensions.GetTempFileName(".dds") }); ddsfiles.Add(new DDSConvertedFile() { sizeX = 128, sizeY = 128, sourceFile = albumArtPath, destinationFile = GeneralExtensions.GetTempFileName(".dds") }); ddsfiles.Add(new DDSConvertedFile() { sizeX = 256, sizeY = 256, sourceFile = albumArtPath, destinationFile = GeneralExtensions.GetTempFileName(".dds") }); // Convert to DDS ToDDS(ddsfiles); // Save for reuse info.ArtFiles = ddsfiles; } foreach (var dds in info.ArtFiles) { packPsarc.AddEntry(String.Format("gfxassets/album_art/album_{0}_{1}.dds", dlcName, dds.sizeX), new FileStream(dds.destinationFile, FileMode.Open, FileAccess.Read, FileShare.Read)); TMPFILES_ART.Add(dds.destinationFile); } // Lyric Art Texture if (File.Exists(info.LyricArtPath)) packPsarc.AddEntry(String.Format("assets/ui/lyrics/{0}/lyrics_{0}.dds", dlcName), new FileStream(info.LyricArtPath, FileMode.Open, FileAccess.Read, FileShare.Read)); // AUDIO var audioFile = info.OggPath; if (File.Exists(audioFile)) if (platform.IsConsole != audioFile.GetAudioPlatform().IsConsole) soundStream = OggFile.ConvertAudioPlatform(audioFile); else soundStream = File.OpenRead(audioFile); else throw new InvalidOperationException(String.Format("Audio file '{0}' not found.", audioFile)); // AUDIO PREVIEW var previewAudioFile = info.OggPreviewPath; if (File.Exists(previewAudioFile)) if (platform.IsConsole != previewAudioFile.GetAudioPlatform().IsConsole) soundPreviewStream = OggFile.ConvertAudioPlatform(previewAudioFile); else soundPreviewStream = File.OpenRead(previewAudioFile); else soundPreviewStream = soundStream; // FLAT MODEL rsenumerableRootStream = new MemoryStream(Resources.rsenumerable_root); packPsarc.AddEntry("flatmodels/rs/rsenumerable_root.flat", rsenumerableRootStream); rsenumerableSongStream = new MemoryStream(Resources.rsenumerable_song); packPsarc.AddEntry("flatmodels/rs/rsenumerable_song.flat", rsenumerableSongStream); using (var toolkitVersionStream = new MemoryStream()) using (var appIdStream = new MemoryStream()) using (var packageListStream = new MemoryStream()) using (var soundbankStream = new MemoryStream()) using (var soundbankPreviewStream = new MemoryStream()) using (var aggregateGraphStream = new MemoryStream()) using (var manifestHeaderHSANStream = new MemoryStream()) using (var manifestHeaderHSONStreamList = new DisposableCollection<Stream>()) using (var manifestStreamList = new DisposableCollection<Stream>()) using (var arrangementStream = new DisposableCollection<Stream>()) using (var showlightStream = new MemoryStream()) using (var xblockStream = new MemoryStream()) { // TOOLKIT VERSION GenerateToolkitVersion(toolkitVersionStream, info.PackageVersion); packPsarc.AddEntry("toolkit.version", toolkitVersionStream); // APP ID if (!platform.IsConsole) { GenerateAppId(appIdStream, info.AppId, platform); packPsarc.AddEntry("appid.appid", appIdStream); } if (platform.platform == GamePlatform.XBox360) { var packageListWriter = new StreamWriter(packageListStream); packageListWriter.Write(dlcName); packageListWriter.Flush(); packageListStream.Seek(0, SeekOrigin.Begin); const string packageList = "PackageList.txt"; packageListStream.WriteTmpFile(packageList, platform); } // SOUNDBANK var soundbankFileName = String.Format("song_{0}", dlcName); var audioFileNameId = SoundBankGenerator2014.GenerateSoundBank(info.Name, soundStream, soundbankStream, info.Volume, platform); packPsarc.AddEntry(String.Format("audio/{0}/{1}.bnk", platform.GetPathName()[0].ToLower(), soundbankFileName), soundbankStream); packPsarc.AddEntry(String.Format("audio/{0}/{1}.wem", platform.GetPathName()[0].ToLower(), audioFileNameId), soundStream); // SOUNDBANK PREVIEW var soundbankPreviewFileName = String.Format("song_{0}_preview", dlcName); dynamic audioPreviewFileNameId; var previewVolume = (float)(info.PreviewVolume ?? info.Volume); if (!soundPreviewStream.Equals(soundStream)) audioPreviewFileNameId = SoundBankGenerator2014.GenerateSoundBank(info.Name + "_Preview", soundPreviewStream, soundbankPreviewStream, previewVolume, platform, true); else audioPreviewFileNameId = SoundBankGenerator2014.GenerateSoundBank(info.Name + "_Preview", soundPreviewStream, soundbankPreviewStream, info.Volume, platform, true, true); packPsarc.AddEntry(String.Format("audio/{0}/{1}.bnk", platform.GetPathName()[0].ToLower(), soundbankPreviewFileName), soundbankPreviewStream); if (!soundPreviewStream.Equals(soundStream)) packPsarc.AddEntry(String.Format("audio/{0}/{1}.wem", platform.GetPathName()[0].ToLower(), audioPreviewFileNameId), soundPreviewStream); // AGGREGATE GRAPH var aggregateGraphFileName = String.Format("{0}_aggregategraph.nt", dlcName); var aggregateGraph = new AggregateGraph2014.AggregateGraph2014(info, platform); aggregateGraph.Serialize(aggregateGraphStream); aggregateGraphStream.Flush(); aggregateGraphStream.Seek(0, SeekOrigin.Begin); packPsarc.AddEntry(aggregateGraphFileName, aggregateGraphStream); var manifestHeader = new ManifestHeader2014<AttributesHeader2014>(platform); var songPartition = new SongPartition(); var songPartitionCount = new SongPartition(); foreach (var arrangement in info.Arrangements) { if (arrangement.ArrangementType == ArrangementType.ShowLight) continue; var arrangementFileName = songPartition.GetArrangementFileName(arrangement.Name, arrangement.ArrangementType).ToLower(); // GAME SONG (SNG) UpdateToneDescriptors(info); GenerateSNG(arrangement, platform); var sngSongFile = File.OpenRead(arrangement.SongFile.File); arrangementStream.Add(sngSongFile); packPsarc.AddEntry(String.Format("songs/bin/{0}/{1}_{2}.sng", platform.GetPathName()[1].ToLower(), dlcName, arrangementFileName), sngSongFile); // XML SONG var xmlSongFile = File.OpenRead(arrangement.SongXml.File); arrangementStream.Add(xmlSongFile); packPsarc.AddEntry(String.Format("songs/arr/{0}_{1}.xml", dlcName, arrangementFileName), xmlSongFile); // MANIFEST var manifest = new Manifest2014<Attributes2014>(); var attribute = new Attributes2014(arrangementFileName, arrangement, info, platform); if (arrangement.ArrangementType != ArrangementType.Vocal) { attribute.SongPartition = songPartitionCount.GetSongPartition(arrangement.Name, arrangement.ArrangementType); if (attribute.SongPartition > 1) { // Make the second arrangement with the same arrangement type as ALTERNATE arrangement ingame attribute.Representative = 0; attribute.ArrangementProperties.Represent = 0; } } var attributeDictionary = new Dictionary<string, Attributes2014> { { "Attributes", attribute } }; manifest.Entries.Add(attribute.PersistentID, attributeDictionary); var manifestStream = new MemoryStream(); manifestStreamList.Add(manifestStream); manifest.Serialize(manifestStream); manifestStream.Seek(0, SeekOrigin.Begin); const string jsonPathPC = "manifests/songs_dlc_{0}/{0}_{1}.json"; const string jsonPathConsole = "manifests/songs_dlc/{0}_{1}.json"; packPsarc.AddEntry(String.Format((platform.IsConsole ? jsonPathConsole : jsonPathPC), dlcName, arrangementFileName), manifestStream); // MANIFEST HEADER var attributeHeaderDictionary = new Dictionary<string, AttributesHeader2014> { { "Attributes", new AttributesHeader2014(attribute) } }; if (platform.IsConsole) { // One for each arrangements (Xbox360/PS3) manifestHeader = new ManifestHeader2014<AttributesHeader2014>(platform); manifestHeader.Entries.Add(attribute.PersistentID, attributeHeaderDictionary); var manifestHeaderStream = new MemoryStream(); manifestHeaderHSONStreamList.Add(manifestHeaderStream); manifestHeader.Serialize(manifestHeaderStream); manifestStream.Seek(0, SeekOrigin.Begin); packPsarc.AddEntry(String.Format("manifests/songs_dlc/{0}_{1}.hson", dlcName, arrangementFileName), manifestHeaderStream); } else { // One for all arrangements (PC/Mac) manifestHeader.Entries.Add(attribute.PersistentID, attributeHeaderDictionary); } } if (!platform.IsConsole) { manifestHeader.Serialize(manifestHeaderHSANStream); manifestHeaderHSANStream.Seek(0, SeekOrigin.Begin); packPsarc.AddEntry(String.Format("manifests/songs_dlc_{0}/songs_dlc_{0}.hsan", dlcName), manifestHeaderHSANStream); } // XML SHOWLIGHTS var shlArr = info.Arrangements.FirstOrDefault(ar => ar.ArrangementType == ArrangementType.ShowLight); if (shlArr != null && shlArr.SongXml.File != null) using (var fs = File.OpenRead(shlArr.SongXml.File)) fs.CopyTo(showlightStream); else { var showlight = new Showlights(info); showlight.Serialize(showlightStream); #if DEBUG // write to file for debugging string shlFilePath = Path.Combine(Path.GetDirectoryName(info.Arrangements[0].SongXml.File), String.Format("{0}_showlights.xml", "CST")); using (FileStream file = new FileStream(shlFilePath, FileMode.Create, FileAccess.Write)) showlightStream.WriteTo(file); #endif } if (showlightStream.CanRead) packPsarc.AddEntry(String.Format("songs/arr/{0}_showlights.xml", dlcName), showlightStream); // XBLOCK GameXblock<Entity2014> game = GameXblock<Entity2014>.Generate2014(info, platform); game.SerializeXml(xblockStream); xblockStream.Flush(); xblockStream.Seek(0, SeekOrigin.Begin); packPsarc.AddEntry(String.Format("gamexblocks/nsongs/{0}.xblock", dlcName), xblockStream); // WRITE PACKAGE packPsarc.Write(output, !platform.IsConsole); output.Flush(); output.Seek(0, SeekOrigin.Begin); output.WriteTmpFile(String.Format("{0}.psarc", dlcName), platform); } } finally { // Dispose all objects if (soundStream != null) soundStream.Dispose(); if (soundPreviewStream != null) soundPreviewStream.Dispose(); if (rsenumerableRootStream != null) rsenumerableRootStream.Dispose(); if (rsenumerableSongStream != null) rsenumerableSongStream.Dispose(); if (pnum == 0) DeleteTmpFiles(TMPFILES_ART); DeleteTmpFiles(TMPFILES_SNG); } }
public Song2014(Sng2014HSL.Sng sngData, Attributes2014 attr = null) { Version = "7"; CrowdSpeed = "1"; if (attr != null) { // If manifest is passed, fill general song information Title = attr.SongName; Arrangement = ((ArrangementName)attr.ArrangementType).ToString(); Part = (short)attr.SongPartition; Offset = (float)attr.SongOffset; CentOffset = Convert.ToString(attr.CentOffset); SongLength = (float)attr.SongLength; SongNameSort = attr.SongNameSort; AverageTempo = attr.SongAverageTempo; Tuning = attr.Tuning; Capo = Convert.ToByte(attr.CapoFret); ArtistName = attr.ArtistName; ArtistNameSort = attr.ArtistNameSort; AlbumName = attr.AlbumName; AlbumNameSort = attr.AlbumNameSort; AlbumYear = Convert.ToString(attr.SongYear) ?? ""; AlbumArt = attr.AlbumArt; ArrangementProperties = attr.ArrangementProperties; LastConversionDateTime = attr.LastConversionDateTime; ToneBase = attr.Tone_Base; ToneA = attr.Tone_A; ToneB = attr.Tone_B; ToneC = attr.Tone_C; ToneD = attr.Tone_D; } else { Part = sngData.Metadata.Part; SongLength = sngData.Metadata.SongLength; Tuning = new TuningStrings(sngData.Metadata.Tuning); Capo = (byte)((sngData.Metadata.CapoFretId == 0xFF) ? 0x00 : sngData.Metadata.CapoFretId); LastConversionDateTime = sngData.Metadata.LastConversionDateTime.ToNullTerminatedAscii(); } Tones = SongTone2014.Parse(sngData.Tones, attr); if (attr == null) { // Fix tones slots for fake tone names if manifest was not entered foreach (var tone in Tones) { if (tone.Name.EndsWith("_0")) { ToneBase = tone.Name; } if (tone.Name.EndsWith("_1")) { ToneA = ToneBase; ToneB = tone.Name; } if (tone.Name.EndsWith("_2")) { ToneC = tone.Name; } if (tone.Name.EndsWith("_3")) { ToneD = tone.Name; } } } //Sections can be obtained from manifest or sng file (manifest preferred) Sections = (attr != null) ? SongSection.Parse(attr.Sections) : SongSection.Parse(sngData.Sections); //Can be obtained from manifest or sng file (sng preferred) Phrases = SongPhrase.Parse(sngData.Phrases); PhraseIterations = SongPhraseIteration2014.Parse(sngData.PhraseIterations); //Can be obtained from manifest or sng file (combined preferred) ChordTemplates = SongChordTemplate2014.Parse(sngData.Chords); // Only SNG have all ChordTemplates, manifest have only chord templates with name if (attr != null) { SongChordTemplate2014.AddChordIds(ChordTemplates, attr.ChordTemplates); // Only manifest has chordIds } //Only in SNG Ebeats = SongEbeat.Parse(sngData.BPMs); StartBeat = sngData.BPMs.BPMs[0].Time; Events = SongEvent.Parse(sngData.Events); Levels = SongLevel2014.Parse(sngData); //Not used in RS2014 customs at this time. Need to check official files NewLinkedDiff = SongNewLinkedDiff.Parse(sngData.NLD); PhraseProperties = SongPhraseProperty.Parse(sngData.PhraseExtraInfo); LinkedDiffs = new SongLinkedDiff[0]; FretHandMuteTemplates = new SongFretHandMuteTemplate[0]; //ddc TranscriptionTrack = TranscriptionTrack2014.GetDefault(); }
// Load RS1 CDLC into PackageCreator public static DLCPackageData RS1LoadFromFolder(string unpackedDir, Platform targetPlatform, bool convert) { var data = new DLCPackageData(); data.Arrangements = new List <Arrangement>(); data.TonesRS2014 = new List <Tone2014>(); data.Tones = new List <Tone>(); data.GameVersion = (convert ? GameVersion.RS2014 : GameVersion.RS2012); data.SignatureType = PackageMagic.CON; // set default volumes data.Volume = (float)-5.5; // - 7 default a little too quite data.PreviewVolume = data.Volume; //Load song manifest var songsManifestJson = Directory.GetFiles(unpackedDir, "songs.manifest.json", SearchOption.AllDirectories); if (songsManifestJson.Length < 1) { throw new DataException("No songs.manifest.json file found."); } if (songsManifestJson.Length > 1) { throw new DataException("More than one songs.manifest.json file found."); } List <Attributes> attr = new List <Attributes>(); var songsManifest = Manifest.Manifest.LoadFromFile(songsManifestJson[0]).Entries.ToArray(); for (int smIndex = 0; smIndex < songsManifest.Count(); smIndex++) { var smData = songsManifest[smIndex].Value.ToArray()[0].Value; attr.Add(smData); } if (attr.FirstOrDefault() == null) { throw new DataException("songs.manifest.json file did not parse correctly."); } // Fill SongInfo data.SongInfo = new SongInfo(); data.SongInfo.SongDisplayName = attr.FirstOrDefault().SongName; data.SongInfo.SongDisplayNameSort = attr.FirstOrDefault().SongNameSort; data.SongInfo.Album = attr.FirstOrDefault().AlbumName; data.SongInfo.SongYear = (attr.FirstOrDefault().SongYear == 0 ? 2012 : attr.FirstOrDefault().SongYear); data.SongInfo.Artist = attr.FirstOrDefault().ArtistName; data.SongInfo.ArtistSort = attr.FirstOrDefault().ArtistNameSort; data.Name = attr.FirstOrDefault().SongKey; //Load tone manifest, even poorly formed tone_bass.manifest.json var toneManifestJson = Directory.GetFiles(unpackedDir, "*tone*.manifest.json", SearchOption.AllDirectories); if (toneManifestJson.Length < 1) { throw new DataException("No tone.manifest.json file found."); } // toolkit produces multiple tone.manifest.json files when packing RS1 CDLC files // rather than change toolkit behavior just merge manifest files for now if (toneManifestJson.Length > 1) { var mergeSettings = new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union }; JObject toneObject1 = new JObject(); foreach (var tone in toneManifestJson) { JObject toneObject2 = JObject.Parse(File.ReadAllText(tone)); //(toneObject1.SelectToken("Entries") as JArray).Merge(toneObject2.SelectToken("Entries")); toneObject1.Merge(toneObject2, mergeSettings); } toneManifestJson = new string[1]; toneManifestJson[0] = Path.Combine(unpackedDir, "merged.tone.manifest"); string json = JsonConvert.SerializeObject(toneObject1, Formatting.Indented); File.WriteAllText(toneManifestJson[0], json); } List <Tone> tones = new List <Tone>(); var toneManifest = Manifest.Tone.Manifest.LoadFromFile(toneManifestJson[0]); for (int tmIndex = 0; tmIndex < toneManifest.Entries.Count(); tmIndex++) { var tmData = toneManifest.Entries[tmIndex]; tones.Add(tmData); } data.Tones = tones; // Load xml arrangements var xmlFiles = Directory.GetFiles(unpackedDir, "*.xml", SearchOption.AllDirectories); if (xmlFiles.Length <= 0) { throw new DataException("Can not find any XML arrangement files"); } List <Tone2014> tones2014 = new List <Tone2014>(); foreach (var xmlFile in xmlFiles) { if (xmlFile.ToLower().Contains("metadata")) // skip DF file { continue; } // some poorly formed RS1 CDLC use just "vocal" if (xmlFile.ToLower().Contains("vocal")) { var voc = new Arrangement(); voc.Name = ArrangementName.Vocals; voc.ArrangementType = ArrangementType.Vocal; voc.ScrollSpeed = 20; voc.SongXml = new SongXML { File = xmlFile }; voc.SongFile = new SongFile { File = "" }; voc.CustomFont = false; // Add Vocal Arrangement data.Arrangements.Add(voc); } else { Attributes2014 attr2014 = new Attributes2014(); Song rsSong = new Song(); bool foundToneForArrangement = false; using (var obj1 = new Rs1Converter()) { rsSong = obj1.XmlToSong(xmlFile); data.SongInfo.AverageTempo = (int)obj1.AverageBPM(rsSong); } // matchup rsSong, songs.manifest, and tone.manifest files foreach (var arrangement in attr) { // apply best guesstimate matching, RS1 CDLC are very inconsistent // TODO: improve accuracy possibly by matching .xblock data string xmlArr = rsSong.Arrangement.ToLowerInvariant(); // var matchLead = Regex.Match(xmlArr.ToLower(), "^lead$", RegexOptions.IgnoreCase); // if(matchLead.Success) if (xmlArr.ToLower().Contains("guitar") && !xmlArr.ToLower().Equals("lead") && !xmlArr.ToLower().Equals("rhythm") && !xmlArr.ToLower().Equals("combo") && !xmlArr.ToLower().Equals("bass")) { if (xmlArr.ToUpper().Equals("PART REAL_GUITAR_22")) // { if (arrangement.ArrangementName.ToLower().Contains("combo")) { rsSong.Arrangement = arrangement.ArrangementName = "Rhythm"; } else { rsSong.Arrangement = arrangement.ArrangementName = "Lead"; } } else { if (arrangement.ArrangementName.ToLower().Contains("combo")) { rsSong.Arrangement = arrangement.ArrangementName = "Rhythm"; } else { rsSong.Arrangement = arrangement.ArrangementName = "Lead"; } } } if (xmlArr.ToLower().Contains("lead") && arrangement.ArrangementName.ToLower().Contains("rhythm")) { rsSong.Arrangement = arrangement.ArrangementName = "Lead"; } if (xmlArr.ToLower().Contains("rhythm") && arrangement.ArrangementName.ToLower().Contains("lead")) { rsSong.Arrangement = arrangement.ArrangementName = "Rhythm"; } if (xmlArr.ToLower().Contains("lead")) { if (!arrangement.ArrangementName.ToLower().Contains("lead")) { continue; } } if (xmlArr.ToLower().Contains("rhythm")) { if (!arrangement.ArrangementName.ToLower().Contains("rhythm")) { continue; } } if (xmlArr.ToLower().Contains("combo")) { if (!arrangement.ArrangementName.ToLower().Contains("combo")) { continue; } } if (xmlArr.ToLower().Contains("bass")) { if (!arrangement.ArrangementName.ToLower().Contains("bass")) { continue; } } if (rsSong.Part == arrangement.SongPartition || tones.Count == 1) // this is inaccurate for some { foreach (var tone in tones) // tone.manifest { if (String.IsNullOrEmpty(arrangement.EffectChainName)) { arrangement.EffectChainName = "Default"; } if (arrangement.EffectChainName.ToLower() == tone.Key.ToLower() || tones.Count == 1) // ok { if (convert) { using (var obj1 = new Rs1Converter()) tones2014.Add(obj1.ToneToTone2014(tone)); // added for consistent naming tone.Name = tones2014[tones2014.Count - 1].Name; tone.Key = tones2014[tones2014.Count - 1].Key; } // load attr2014 with RS1 mapped values for use by Arrangement() attr2014.Tone_Base = tone.Name; attr2014.ArrangementName = arrangement.ArrangementName; attr2014.CentOffset = 0; attr2014.DynamicVisualDensity = new List <float>() { 2 }; attr2014.SongPartition = arrangement.SongPartition; attr2014.PersistentID = IdGenerator.Guid().ToString(); attr2014.MasterID_RDV = RandomGenerator.NextInt(); attr2014.ArrangementProperties = new SongArrangementProperties2014(); if (arrangement.ArrangementName.ToLower().Contains("lead")) { attr2014.ArrangementType = 0; attr2014.ArrangementProperties.RouteMask = 1; } else if (arrangement.ArrangementName.ToLower().Contains("rhythm")) { attr2014.ArrangementType = 1; attr2014.ArrangementProperties.RouteMask = 2; } else if (arrangement.ArrangementName.ToLower().Contains("combo")) { attr2014.ArrangementType = 2; attr2014.ArrangementProperties.RouteMask = arrangement.EffectChainName.ToLower().Contains("lead") ? 1 : 2; } else if (arrangement.ArrangementName.ToLower().Contains("bass")) { attr2014.ArrangementType = 3; attr2014.ArrangementProperties.RouteMask = 4; } else { // some RS1 CDLC do not have a valid ArrangementName if (rsSong.Arrangement.ToLower().Contains("guitar")) { attr2014.ArrangementName = "Lead"; attr2014.ArrangementType = 0; attr2014.ArrangementProperties.RouteMask = 1; } else if (rsSong.Arrangement.ToLower().Contains("bass")) { attr2014.ArrangementName = "Bass"; attr2014.ArrangementType = 3; attr2014.ArrangementProperties.RouteMask = 4; } else // default to rhythm { attr2014.ArrangementName = "Rhythm"; attr2014.ArrangementType = 1; attr2014.ArrangementProperties.RouteMask = 2; } } if (arrangement.Tuning == "E Standard") { rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } } ; else if (arrangement.Tuning == "DropD") { rsSong.Tuning = new TuningStrings { String0 = -2, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } } ; else if (arrangement.Tuning == "OpenG") { rsSong.Tuning = new TuningStrings { String0 = -2, String1 = -2, String2 = 0, String3 = 0, String4 = 0, String5 = -2 } } ; else if (arrangement.Tuning == "EFlat") { rsSong.Tuning = new TuningStrings { String0 = -1, String1 = -1, String2 = -1, String3 = -1, String4 = -1, String5 = -1 } } ; else // default to standard tuning { rsSong.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } }; foundToneForArrangement = true; break; } } } if (foundToneForArrangement) { break; } } if (!foundToneForArrangement) { Console.WriteLine(@"Could not determine the arrangement tone pairing"); } // write the tones to file using (var obj1 = new Rs1Converter()) obj1.SongToXml(rsSong, xmlFile, true); if (convert) // RS1 -> RS2 { Song2014 rsSong2014 = new Song2014(); using (var obj1 = new Rs1Converter()) rsSong2014 = obj1.SongToSong2014(rsSong); using (var obj2 = new Rs2014Converter()) obj2.Song2014ToXml(rsSong2014, xmlFile, true); } // Adding Song Arrangement try { data.Arrangements.Add(new Arrangement(attr2014, xmlFile)); } catch (Exception ex) { // mainly for the benifit of convert2012 CLI users Console.WriteLine(@"This CDLC could not be auto converted." + Environment.NewLine + "You can still try manually adding the arrangements and assests." + Environment.NewLine + ex.Message); } } } data.TonesRS2014 = tones2014; //Get Album Artwork DDS Files var artFiles = Directory.GetFiles(unpackedDir, "*.dds", SearchOption.AllDirectories); if (artFiles.Length < 1) { throw new DataException("No Album Artwork file found."); } if (artFiles.Length > 1) { throw new DataException("More than one Album Artwork file found."); } var targetArtFiles = new List <DDSConvertedFile>(); data.AlbumArtPath = artFiles[0]; targetArtFiles.Add(new DDSConvertedFile() { sizeX = 256, sizeY = 256, sourceFile = artFiles[0], destinationFile = artFiles[0].CopyToTempFile(".dds") }); data.ArtFiles = targetArtFiles; //Audio files var targetAudioFiles = new List <string>(); var audioFiles = Directory.GetFiles(unpackedDir, "*.ogg", SearchOption.AllDirectories); if (audioFiles.Length < 1) { throw new DataException("No Audio file found."); } if (audioFiles.Length > 2) { throw new DataException("Too many Audio files found."); } int i; for (i = 0; i < audioFiles.Length; i++) { if (convert && audioFiles[i].Contains("_fixed.ogg")) // use it { break; } if (!convert && !audioFiles[i].Contains("_fixed.ogg")) { break; } } var sourcePlatform = unpackedDir.GetPlatform(); if (targetPlatform.IsConsole != (sourcePlatform = audioFiles[i].GetAudioPlatform()).IsConsole) { var newFile = Path.Combine(Path.GetDirectoryName(audioFiles[i]), String.Format("{0}_cap.ogg", Path.GetFileNameWithoutExtension(audioFiles[i]))); OggFile.ConvertAudioPlatform(audioFiles[i], newFile); audioFiles[i] = newFile; } targetAudioFiles.Add(audioFiles[i]); if (!targetAudioFiles.Any()) { throw new DataException("Audio file not found."); } FileInfo a = new FileInfo(audioFiles[i]); data.OggPath = a.FullName; //AppID if (!convert) { var appidFile = Directory.GetFiles(unpackedDir, "*APP_ID*", SearchOption.AllDirectories); if (appidFile.Length > 0) { data.AppId = File.ReadAllText(appidFile[0]); } } else { data.AppId = "248750"; } //Package version var versionFile = Directory.GetFiles(unpackedDir, "toolkit.version", SearchOption.AllDirectories); if (versionFile.Length > 0) { data.PackageVersion = GeneralExtensions.ReadPackageVersion(versionFile[0]); } else { data.PackageVersion = "1"; } if (convert) { data.Tones = null; } return(data); }