public void ReadSong(Song2014 songXml, Sng2014File sngFile) { Int16[] tuning = { songXml.Tuning.String0, songXml.Tuning.String1, songXml.Tuning.String2, songXml.Tuning.String3, songXml.Tuning.String4, songXml.Tuning.String5, }; parseEbeats(songXml, sngFile); parsePhrases(songXml, sngFile); parseChords(songXml, sngFile, tuning, songXml.Arrangement == "Bass"); // vocals use different parse function sngFile.Vocals = new VocalSection { Vocals = new Vocal[0] }; parsePhraseIterations(songXml, sngFile); parsePhraseExtraInfo(songXml, sngFile); parseNLD(songXml, sngFile); parseActions(songXml, sngFile); parseEvents(songXml, sngFile); parseTones(songXml, sngFile); parseDNAs(songXml, sngFile); parseSections(songXml, sngFile); parseArrangements(songXml, sngFile); parseMetadata(songXml, sngFile, tuning); // this needs to be initialized after arrangements parseChordNotes(songXml, sngFile); }
/// <param name="song"></param> /// <param name="difficultyLevel">null = highest level available</param> public static Score GetScoreForMaxDifficultyLevel(Song2014 song, int? difficultyLevel) { List<PhraseIterationWithEndTime> iterationsWithEndTime = PhraseIterationWithEndTime.listFromBaseArray(song.PhraseIterations); IEnumerable<SongNoteChordWrapper> allSounds = Enumerable.Empty<SongNoteChordWrapper>(); for (int phraseId = 0; phraseId < song.Phrases.Length;phraseId++) { var phrase = song.Phrases[phraseId]; var diffLevel = phrase.MaxDifficulty; if (difficultyLevel.HasValue && difficultyLevel < diffLevel) diffLevel = difficultyLevel.Value; var selectedLevel = song.Levels.FirstOrDefault(x => x.Difficulty == diffLevel); var phraseIterations = iterationsWithEndTime.Where(x => x.PhraseId == phraseId).ToArray(); for (int i = 0; i < phraseIterations.Length; i++) { var iterationWithEndTime = phraseIterations[i]; var notes = selectedLevel.Notes.Where(x => iterationWithEndTime.contains(x.Time)); var chords = selectedLevel.Chords.Where(x => iterationWithEndTime.contains(x.Time)); allSounds = allSounds.Union(notes.Select(x => new SongNoteChordWrapper(x))) .Union(chords.Select(x => new SongNoteChordWrapper(x))); } } var score = CreateSong(song, allSounds); return score; }
public Song Song2014ToSong(Song2014 rs2014Song) { var rs1Song = new Song(); AddSongMetadata(rs2014Song, rs1Song); AddElements(rs2014Song, rs1Song); AddDifferences(rs2014Song, rs1Song); return rs1Song; }
public AttributesHeader2014(string arrangementFileName, Arrangement arrangement, DLCPackageData info, Platform platform) { IsVocal = arrangement.ArrangementType == Sng.ArrangementType.Vocal; SongContent = (IsVocal) ? null : Song2014.LoadFromFile(arrangement.SongXml.File); var dlcName = info.Name.ToLower(); var albumUrn = String.Format(URN_TEMPLATE, TagValue.Image.GetDescription(), TagValue.DDS.GetDescription(), String.Format("album_{0}", dlcName)); var jsonUrn = String.Format(URN_TEMPLATE, TagValue.Database.GetDescription(), TagValue.JsonDB.GetDescription(), String.Format("{0}_{1}", dlcName, arrangementFileName)); //FILL ATTRIBUTES this.AlbumArt = albumUrn; ArrangementName = arrangement.Name.ToString(); DLC = true; DLCKey = info.Name; LeaderboardChallengeRating = 0; ManifestUrn = jsonUrn; MasterID_RDV = arrangement.MasterId; PersistentID = arrangement.Id.ToString().Replace("-", "").ToUpper(); Shipping = true; SKU = "RS2"; SongKey = info.Name; if (!IsVocal) { AlbumName = AlbumNameSort = info.SongInfo.Album; ArtistName = info.SongInfo.Artist; CentOffset = arrangement.TuningPitch != 0 ? TuningFrequency.Frequency2Cents(arrangement.TuningPitch) : 0.0; ArtistNameSort = info.SongInfo.ArtistSort; CapoFret = (arrangement.Sng2014.Metadata.CapoFretId == 0xFF) ? CapoFret = 0 : Convert.ToDecimal(arrangement.Sng2014.Metadata.CapoFretId); DNA_Chords = arrangement.Sng2014.DNACount[(int) DNAId.Chord]; DNA_Riffs = arrangement.Sng2014.DNACount[(int) DNAId.Riff]; DNA_Solo = arrangement.Sng2014.DNACount[(int) DNAId.Solo]; NotesEasy = arrangement.Sng2014.NoteCount[0]; NotesMedium = arrangement.Sng2014.NoteCount[1]; NotesHard = arrangement.Sng2014.NoteCount[2]; EasyMastery = NotesEasy / NotesHard; MediumMastery = NotesMedium / NotesHard; Representative = Convert.ToInt32(!arrangement.BonusArr); RouteMask = (int)arrangement.RouteMask; // TODO this is not quite it but much closer SongDiffEasy = SongContent.SongLength / NotesEasy; SongDiffMed = SongContent.SongLength / NotesMedium; SongDiffHard = SongContent.SongLength / NotesHard; SongDifficulty = SongDiffHard; SongLength = (double?)Math.Round(SongContent.SongLength, 3, MidpointRounding.AwayFromZero); SongName = info.SongInfo.SongDisplayName; SongNameSort = info.SongInfo.SongDisplayNameSort; SongYear = info.SongInfo.SongYear; var tunDef = TuningDefinitionRepository.Instance().Select(arrangement.Tuning, platform.version); Tuning = tunDef.Tuning; } }
public void Convert(string zigSrcPath, string destPath) { var deser = new XmlSerializer(typeof(ZpeSong)); ZpeSong zigSong; using (FileStream stream = new FileStream(zigSrcPath, FileMode.Open)) { zigSong = (ZpeSong)deser.Deserialize(stream); } if (zigSong.PueVersion != 46) throw new Exception("Incompatable version of Ziggy Pro Editor XML file"); bool foundTrack = false; StringBuilder sb = new StringBuilder(); // cross matching arrangment arrays string[] rsArray = new string[] { "Lead", "Rhythm", "Bass" }; string[] zigArray = new string[] { "PART REAL_GUITAR_22", "PART REAL_GUITAR", "PART REAL_BASS_22" }; int arrIndex = -1; foreach (var arrangement in zigArray) { arrIndex++; var guitarTrack = zigSong.Tracks.SingleOrDefault(tr => arrangement.Equals(tr.Name)); if (guitarTrack == null) { continue; //throw new Exception("Couldn't find a guitar track"); } foundTrack = true; var rsSong = new Song2014(); AddSongMetadata(rsSong, zigSong, rsArray[arrIndex]); AddEbeats(rsSong, zigSong, arrangement); AddNotes(rsSong, zigSong, arrangement); AddToneProps(rsSong, rsArray[arrIndex]); var destDir = Path.GetDirectoryName(destPath); var destName = Path.GetFileNameWithoutExtension(destPath); var xmlDestPath = String.Format("{0}_{1}.xml", Path.Combine(destDir, destName), rsArray[arrIndex]); using (FileStream stream = new FileStream(xmlDestPath, FileMode.Create)) { rsSong.Serialize(stream, true); } } if (!foundTrack) throw new NullReferenceException("Did not find any Rocksmith 2014 compatible Ziggy Pro tracks in " + Path.GetFileName(zigSrcPath) + Environment.NewLine); }
private static void AddSongMetadata(Song2014 rsSong, ZpeSong zigSong, string arrangment) { // standard meta header data rsSong.Version = "7"; rsSong.Arrangement = arrangment; rsSong.Part = 1; rsSong.Offset = 0; rsSong.CentOffset = "0"; rsSong.StartBeat = 0; rsSong.Capo = 0; rsSong.AlbumName = "Unknown Album"; rsSong.AlbumYear = DateTime.Now.ToString("yyyy"); rsSong.CrowdSpeed = "1"; rsSong.LastConversionDateTime = DateTime.Now.ToString(); rsSong.SongLength = zigSong.Length; Regex regex = new Regex(" - "); string[] artistTitle = regex.Split(zigSong.Name); rsSong.ArtistName = artistTitle[0] == null ? zigSong.Name : artistTitle[0]; rsSong.Title = artistTitle[1] == null ? zigSong.Name : artistTitle[1]; ZpeTempo tempo = zigSong.Tracks[0].Tempos[0]; float BPM = (float)Math.Round((float)60000000 / tempo.RawTempo, 3); rsSong.AverageTempo = BPM; ZpeTuning tuning = null; for (int i = 0; i < zigSong.Tunings.Tuning.Count; i++) { if (arrangment == "Lead" || arrangment == "Rhythm") if (zigSong.Tunings.Tuning[i].IsGuitarTuning) { tuning = zigSong.Tunings.Tuning[i]; break; } if (arrangment == "Bass") if (zigSong.Tunings.Tuning[i].IsBassTuning) { tuning = zigSong.Tunings.Tuning[i]; break; } } if (tuning == null) throw new Exception("ZPE XML does not contain tuning"); rsSong.Tuning = new TuningStrings { String0 = tuning.E, String1 = tuning.A, String2 = tuning.D, String3 = tuning.G, String4 = tuning.B, String5 = tuning.HighE }; }
/// <param name="song"></param> /// <param name="difficultyLevel">null = highest level available</param> public static Score GetScoreForExactDifficultyLevel(Song2014 song, int? difficultyLevel) { SongLevel2014 selectedLevel; if(difficultyLevel.HasValue) selectedLevel = song.Levels.FirstOrDefault(x => x.Difficulty == difficultyLevel); else selectedLevel = song.Levels.OrderBy(x => x.Difficulty).LastOrDefault(); if (selectedLevel == null) return null; var allSounds = selectedLevel.Notes.Select(x => new SongNoteChordWrapper(x)) .Union(selectedLevel.Chords.Select(x => new SongNoteChordWrapper(x))); var score = CreateSong(song, allSounds); return score; }
/// <summary> /// Convert RS2014 (Song2014) to XML file /// </summary> /// <param name="rs2014Song"></param> /// <param name="outputPath"></param> /// <param name="overWrite"></param> /// <returns>RS2014 XML file path</returns> public string Song2014ToXml(Song2014 rs2014Song, string outputPath, bool overWrite) { if (File.Exists(outputPath) && overWrite) File.Delete(outputPath); else { var outputDir = Path.GetDirectoryName(outputPath); var outputFile = String.Format("{0}_{1}", rs2014Song.Title, rs2014Song.Arrangement); outputFile = String.Format("{0}{1}", outputFile.GetValidName(false, true).ToLower(), "_rs2014.xml"); outputPath = Path.Combine(outputDir, outputFile); } using (var stream = File.OpenWrite(outputPath)) { rs2014Song.Serialize(stream, false); } return outputPath; }
private void AddSongMetadata(Song2014 rs2014Song, Song rs1Song) { // for consistency apply old naming method ;( rs1Song.Title = String.Format("{0} - {1}", rs2014Song.Title, rs2014Song.Arrangement); if (rs2014Song.Part > 1) rs1Song.Title = String.Format("{0} {1}", rs1Song.Title, rs2014Song.Part); rs1Song.Arrangement = rs2014Song.Arrangement; rs1Song.Part = rs2014Song.Part; rs1Song.Offset = rs2014Song.Offset; rs1Song.SongLength = rs2014Song.SongLength; rs1Song.StartBeat = rs2014Song.StartBeat; rs1Song.AverageTempo = rs2014Song.AverageTempo; rs1Song.Tuning = rs2014Song.Tuning; rs1Song.Artist = rs2014Song.ArtistName; rs1Song.AlbumName = rs2014Song.AlbumName; rs1Song.AlbumYear = rs2014Song.AlbumYear; // use correct LastConversionDateTime format rs1Song.LastConversionDateTime = DateTime.Now.ToString("MM-dd-yy HH:mm"); }
static void ExportArrangement(Score score, Song2014 arrangement, string identifier, int difficulty, string originalFile, ToolkitInfo toolkitInfo) { var track = Converter.ConvertArrangement(arrangement, identifier, difficulty); score.Tracks.Add(track); score.Title = arrangement.Title; score.Artist = arrangement.ArtistName; score.ArtistSort = arrangement.ArtistNameSort; score.Album = arrangement.AlbumName; score.Year = arrangement.AlbumYear; score.Comments = new List<string>(); score.Comments.Add("Generated by RocksmithToTab v" + VersionInfo.VERSION); score.Comments.Add("=> http://www.rocksmithtotab.de"); score.Comments.Add("Created from archive: " + Path.GetFileName(originalFile)); if (toolkitInfo != null && toolkitInfo.PackageAuthor != string.Empty) { score.Comments.Add("CDLC author: " + toolkitInfo.PackageAuthor); score.Tabber = toolkitInfo.PackageAuthor; } if (toolkitInfo != null && toolkitInfo.PackageVersion != string.Empty) score.Comments.Add("CDLC version: " + toolkitInfo.PackageVersion); }
public string SongFile2Song2014File(string songFilePath, bool overWrite) { Song2014 song2014 = new Song2014(); using (var obj = new Rs1Converter()) song2014 = obj.SongToSong2014(Song.LoadFromFile(songFilePath)); if (!overWrite) { var srcDir = Path.GetDirectoryName(songFilePath); var srcName = Path.GetFileNameWithoutExtension(songFilePath); var backupSrcPath = String.Format("{0}_{1}.xml", Path.Combine(srcDir, srcName), "RS1"); // backup original RS1 file File.Copy(songFilePath, backupSrcPath); } // write converted RS1 file using (FileStream stream = new FileStream(songFilePath, FileMode.Create)) song2014.Serialize(stream, true); return songFilePath; }
private void parseMetadata(Song2014 xml, Sng2014File sng, Int16[] tuning) { // Easy, Medium, Hard NoteCount = new int[3]; NoteCount[0] = getNoteCount(sng, 0); NoteCount[1] = getNoteCount(sng, 1); NoteCount[2] = getNoteCount(sng, 2); sng.Metadata = new Metadata(); sng.Metadata.MaxScore = 100000; sng.Metadata.MaxDifficulty = getMaxDifficulty(xml); sng.Metadata.MaxNotesAndChords = NoteCount[2]; sng.Metadata.MaxNotesAndChords_Real = sng.Metadata.MaxNotesAndChords;//num unique notes+not ignored sng.Metadata.PointsPerNote = sng.Metadata.MaxScore / sng.Metadata.MaxNotesAndChords; sng.Metadata.FirstBeatLength = xml.Ebeats[1].Time - xml.Ebeats[0].Time; sng.Metadata.StartTime = xml.Offset * -1; sng.Metadata.CapoFretId = (xml.Capo == 0) ? unchecked((Byte)(-1)) : xml.Capo; readString(xml.LastConversionDateTime, sng.Metadata.LastConversionDateTime); sng.Metadata.Part = xml.Part; sng.Metadata.SongLength = xml.SongLength; sng.Metadata.StringCount = 6; sng.Metadata.Tuning = tuning ?? new Int16[sng.Metadata.StringCount]; // calculated when parsing arrangements sng.Metadata.Unk11_FirstNoteTime = first_note_time; sng.Metadata.Unk12_FirstNoteTime = first_note_time; }
private void parseEvents(Song2014 xml, Sng2014File sng) { sng.Events = new EventSection(); sng.Events.Count = xml.Events.Length; sng.Events.Events = new Event[sng.Events.Count]; for (int i = 0; i < sng.Events.Count; i++) { var evnt = xml.Events[i]; var e = new Event(); e.Time = evnt.Time; readString(evnt.Code, e.EventName); sng.Events.Events[i] = e; } }
private void parseEbeats(Song2014 xml, Sng2014File sng) { sng.BPMs = new BpmSection(); sng.BPMs.Count = xml.Ebeats.Length; sng.BPMs.BPMs = new Bpm[sng.BPMs.Count]; Int16 measure = 0; Int16 beat = 0; for (int i = 0; i < sng.BPMs.Count; i++) { var ebeat = xml.Ebeats[i]; var bpm = new Bpm(); bpm.Time = ebeat.Time; if (ebeat.Measure >= 0) { measure = ebeat.Measure; beat = 0; } else { beat++; } bpm.Measure = measure; bpm.Beat = beat; bpm.PhraseIteration = getPhraseIterationId(xml, bpm.Time, true); if (beat == 0) { bpm.Mask |= 1; if (measure % 2 == 0) bpm.Mask |= 2; } sng.BPMs.BPMs[i] = bpm; } }
private void parseDNAs(Song2014 xml, Sng2014File sng) { sng.DNAs = new DnaSection(); List<Dna> dnas = new List<Dna>(); DNACount = new int[4]; // based on events: dna_none=0, dna_solo=1, dna_riff=2, dna_chord=3 foreach (var e in xml.Events) { Int32 id = -1; switch (e.Code) { case "dna_none": id = 0; break; case "dna_solo": id = 1; break; case "dna_riff": id = 2; break; case "dna_chord": id = 3; break; } if (id != -1) { var dna = new Dna(); dna.Time = e.Time; dna.DnaId = id; DNACount[id] += 1; dnas.Add(dna); } } sng.DNAs.Dnas = dnas.ToArray(); sng.DNAs.Count = sng.DNAs.Dnas.Length; }
private Song2014 ConvertPhraseIterations(Song rsSong, Song2014 rsSong2014) { var phraseIterations = new List<SongPhraseIteration2014>(); foreach (var songPhraseIteration in rsSong.PhraseIterations) { // HeroLevels set to null -> prevent some hangs phraseIterations.Add(new SongPhraseIteration2014 { PhraseId = songPhraseIteration.PhraseId, HeroLevels = null, Time = songPhraseIteration.Time }); } rsSong2014.PhraseIterations = phraseIterations.ToArray(); return rsSong2014; }
private Song2014 ConvertChordTemplates(Song rsSong, Song2014 rsSong2014) { // add chordTemplates elements var chordTemplate = new List<SongChordTemplate2014>(); foreach (var songChordTemplate in rsSong.ChordTemplates) { // tested ... not the source of game hangs //if (String.IsNullOrEmpty(songChordTemplate.ChordName)) // continue; chordTemplate.Add(new SongChordTemplate2014 { ChordName = songChordTemplate.ChordName, DisplayName = songChordTemplate.ChordName, Finger0 = (sbyte)songChordTemplate.Finger0, Finger1 = (sbyte)songChordTemplate.Finger1, Finger2 = (sbyte)songChordTemplate.Finger2, Finger3 = (sbyte)songChordTemplate.Finger3, Finger4 = (sbyte)songChordTemplate.Finger4, Finger5 = (sbyte)songChordTemplate.Finger5, Fret0 = (sbyte)songChordTemplate.Fret0, Fret1 = (sbyte)songChordTemplate.Fret1, Fret2 = (sbyte)songChordTemplate.Fret2, Fret3 = (sbyte)songChordTemplate.Fret3, Fret4 = (sbyte)songChordTemplate.Fret4, Fret5 = (sbyte)songChordTemplate.Fret5 }); } // tested ... not the source of game hangs // get rid of duplicate chords if any // chordTemplate = chordTemplate.Distinct().ToList(); // tested ... could be source of game hangs if (rsSong.ChordTemplates == null) { Console.WriteLine("Applied fix to RS1->RS2 ChordTemplates conversion"); rsSong2014.ChordTemplates = new SongChordTemplate2014[0]; } else rsSong2014.ChordTemplates = chordTemplate.ToArray(); return rsSong2014; }
// 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; }
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 void parseNLD(Song2014 xml, Sng2014File sng) { sng.NLD = new NLinkedDifficultySection(); sng.NLD.Count = xml.NewLinkedDiff.Length; sng.NLD.NLinkedDifficulties = new NLinkedDifficulty[sng.NLD.Count]; for (int i = 0; i < sng.NLD.Count; i++) { var nld = xml.NewLinkedDiff[i]; var n = new NLinkedDifficulty(); // TODO: Ratio attribute unused? n.LevelBreak = nld.LevelBreak; n.PhraseCount = nld.PhraseCount; n.NLD_Phrase = new Int32[n.PhraseCount]; for (int j = 0; j < n.PhraseCount; j++) { n.NLD_Phrase[j] = nld.Nld_phrase[j].Id; } sng.NLD.NLinkedDifficulties[i] = n; } }
private void parseNote(Song2014 xml, SongNote2014 note, Notes n, Notes prev) { n.NoteMask = parseNoteMask(note, true); // numbering (NoteFlags) will be set later n.Time = note.Time; n.StringIndex = note.String; // actual fret number n.FretId = (Byte)note.Fret; // anchor fret will be set later n.AnchorFretId = unchecked((Byte)(-1)); // will be overwritten n.AnchorWidth = unchecked((Byte)(-1)); n.ChordId = -1; n.ChordNotesId = -1; n.PhraseIterationId = getPhraseIterationId(xml, n.Time, false); n.PhraseId = xml.PhraseIterations[n.PhraseIterationId].PhraseId; // these will be overwritten n.FingerPrintId[0] = -1; n.FingerPrintId[1] = -1; // these will be overwritten n.NextIterNote = -1; n.PrevIterNote = -1; n.ParentPrevNote = -1; n.SlideTo = unchecked((Byte)note.SlideTo); n.SlideUnpitchTo = unchecked((Byte)note.SlideUnpitchTo); n.LeftHand = unchecked((Byte)note.LeftHand); // 'bvibrato' and 'rchords8' are using 0 value but without TAP mask if (note.Tap != 0) n.Tap = unchecked((Byte)note.Tap); else n.Tap = unchecked((Byte)(-1)); n.PickDirection = (Byte)note.PickDirection; n.Slap = (Byte)note.Slap; n.Pluck = (Byte)note.Pluck; n.Vibrato = note.Vibrato; n.Sustain = note.Sustain; n.MaxBend = note.Bend; n.BendData = new BendDataSection(); n.BendData.BendData = parseBendData(note, true); n.BendData.Count = n.BendData.BendData.Length; }
private void parseActions(Song2014 xml, Sng2014File sng) { // there is no XML example, EOF does not support it either sng.Actions = new ActionSection(); sng.Actions.Count = 0; sng.Actions.Actions = new Action[sng.Actions.Count]; // no RS2 SNG is using this // for (int i = 0; i < sng.Actions.Count; i++) { // //var action = xml.?[i]; // var a = new Action(); // //a.Time = action.Time; // //read_string(action.ActionName, a.ActionName); // sng.Actions.Actions[i] = a; // } }
/// <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); 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) { 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 void parseArrangements(Song2014 xml, Sng2014File sng) { sng.Arrangements = new ArrangementSection(); sng.Arrangements.Count = getMaxDifficulty(xml) + 1; sng.Arrangements.Arrangements = new Arrangement[sng.Arrangements.Count]; // not strictly necessary but more helpful than hash value var note_id = new Dictionary<UInt32, UInt32>(); for (int i = 0; i < sng.Arrangements.Count; i++) { var level = xml.Levels[i]; var a = new Arrangement(); a.Difficulty = level.Difficulty; var anchors = new AnchorSection(); anchors.Count = level.Anchors.Length; anchors.Anchors = new Anchor[anchors.Count]; for (int j = 0; j < anchors.Count; j++) { var anchor = new Anchor(); anchor.StartBeatTime = level.Anchors[j].Time; if (j + 1 < anchors.Count) anchor.EndBeatTime = level.Anchors[j + 1].Time; else // last phrase iteration = noguitar/end anchor.EndBeatTime = xml.PhraseIterations[xml.PhraseIterations.Length - 1].Time; // TODO: not 100% clear // times will be updated later // these "garbage" values are everywhere! //anchor.Unk3_FirstNoteTime = (float) 3.4028234663852886e+38; //anchor.Unk4_LastNoteTime = (float) 1.1754943508222875e-38; anchor.FretId = (byte)level.Anchors[j].Fret; anchor.Width = (Int32)level.Anchors[j].Width; anchor.PhraseIterationId = getPhraseIterationId(xml, anchor.StartBeatTime, false); anchors.Anchors[j] = anchor; } a.Anchors = anchors; // each slideTo will get anchor extension a.AnchorExtensions = new AnchorExtensionSection(); foreach (var note in level.Notes) if (note.SlideTo != -1) ++a.AnchorExtensions.Count; a.AnchorExtensions.AnchorExtensions = new AnchorExtension[a.AnchorExtensions.Count]; // Fingerprints1 is for handshapes without "arp" displayName a.Fingerprints1 = new FingerprintSection(); // Fingerprints2 is for handshapes with "arp" displayName a.Fingerprints2 = new FingerprintSection(); var fp1 = new List<Fingerprint>(); var fp2 = new List<Fingerprint>(); foreach (var h in level.HandShapes) { if (h.ChordId < 0) continue; var fp = new Fingerprint { ChordId = h.ChordId, StartTime = h.StartTime, EndTime = h.EndTime // TODO: not always StartTime //fp.Unk3_FirstNoteTime = fp.StartTime; //fp.Unk4_LastNoteTime = fp.StartTime; }; if (xml.ChordTemplates[fp.ChordId].DisplayName.EndsWith("arp")) fp2.Add(fp); else fp1.Add(fp); } a.Fingerprints1.Count = fp1.Count; a.Fingerprints1.Fingerprints = fp1.ToArray(); a.Fingerprints2.Count = fp2.Count; a.Fingerprints2.Fingerprints = fp2.ToArray(); // calculated as we go through notes, seems to work // NotesInIteration1 is count without ignore="1" notes a.PhraseIterationCount1 = xml.PhraseIterations.Length; a.NotesInIteration1 = new Int32[a.PhraseIterationCount1]; // NotesInIteration2 seems to be the full count a.PhraseIterationCount2 = a.PhraseIterationCount1; a.NotesInIteration2 = new Int32[a.PhraseIterationCount2]; // notes and chords sorted by time List<Notes> notes = new List<Notes>(); int acent = 0; foreach (var note in level.Notes) { var n = new Notes(); Notes prev = null; if (notes.Count > 0) prev = notes.Last(); parseNote(xml, note, n, prev); notes.Add(n); for (int j = 0; j < xml.PhraseIterations.Length; j++) { var piter = xml.PhraseIterations[j]; if (piter.Time > note.Time) { if (note.Ignore == 0) ++a.NotesInIteration1[j - 1]; ++a.NotesInIteration2[j - 1]; break; } } if (note.SlideTo != -1) { var ae = new AnchorExtension(); ae.FretId = (Byte)note.SlideTo; ae.BeatTime = note.Time + note.Sustain; a.AnchorExtensions.AnchorExtensions[acent++] = ae; } } foreach (var chord in level.Chords) { var cn = new Notes(); Int32 id = -1; if (chord.ChordNotes != null && chord.ChordNotes.Length > 0) id = addChordNotes(sng, chord); parseChord(xml, sng, chord, cn, id); notes.Add(cn); for (int j = 0; j < xml.PhraseIterations.Length; j++) { var piter = xml.PhraseIterations[j]; if (chord.Time >= piter.Time && piter.Time >= chord.Time) { if (chord.Ignore == 0) ++a.NotesInIteration1[j]; ++a.NotesInIteration2[j]; // j-1 not safe with j=0 break; } } } // exception handler for some poorly formed RS1 CDLC try { // need to be sorted before anchor note times are updated notes.Sort((x, y) => x.Time.CompareTo(y.Time)); // check for RS1 CDLC note time errors // if (notes.Count > 0) // alt method to deal with the exception if ((int)first_note_time == 0 || first_note_time > notes[0].Time) first_note_time = notes[0].Time; } catch (Exception) { // show error in convert2012CLI command window and continue Console.WriteLine(@" -- CDLC contains note time errors and may not play properly"); // + ex.Message); } foreach (var n in notes) { for (Int16 id = 0; id < fp1.Count; id++) //FingerPrints 1st level (common handshapes?) if (n.Time >= fp1[id].StartTime && n.Time < fp1[id].EndTime) { n.FingerPrintId[0] = id; // add STRUM to chords if highDensity = 0 if (n.ChordId != -1 && (n.NoteMask & CON.NOTE_MASK_HIGHDENSITY) != CON.NOTE_MASK_HIGHDENSITY) n.NoteMask |= CON.NOTE_MASK_STRUM; if (fp1[id].Unk3_FirstNoteTime == 0) fp1[id].Unk3_FirstNoteTime = n.Time; float sustain = 0; if (n.Time + n.Sustain < fp1[id].EndTime) sustain = n.Sustain; fp1[id].Unk4_LastNoteTime = n.Time + sustain; break; } for (Int16 id = 0; id < fp2.Count; id++) //FingerPrints 2nd level (used for -arp(eggio) handshapes) if (n.Time >= fp2[id].StartTime && n.Time < fp2[id].EndTime) { n.FingerPrintId[1] = id; // add STRUM to chords if (fp2[id].StartTime == n.Time && n.ChordId != -1) n.NoteMask |= CON.NOTE_MASK_STRUM; n.NoteMask |= CON.NOTE_MASK_ARPEGGIO; if (fp2[id].Unk3_FirstNoteTime == 0) fp2[id].Unk3_FirstNoteTime = n.Time; float sustain = 0; if (n.Time + n.Sustain < fp2[id].EndTime) sustain = n.Sustain; fp2[id].Unk4_LastNoteTime = n.Time + sustain; break; } for (int j = 0; j < a.Anchors.Count; j++) if (n.Time >= a.Anchors.Anchors[j].StartBeatTime && n.Time < a.Anchors.Anchors[j].EndBeatTime) { n.AnchorWidth = (Byte)a.Anchors.Anchors[j].Width; // anchor fret n.AnchorFretId = (Byte)a.Anchors.Anchors[j].FretId; if (a.Anchors.Anchors[j].Unk3_FirstNoteTime == 0) a.Anchors.Anchors[j].Unk3_FirstNoteTime = n.Time; float sustain = 0; if (n.Time + n.Sustain < a.Anchors.Anchors[j].EndBeatTime - 0.1) sustain = n.Sustain; a.Anchors.Anchors[j].Unk4_LastNoteTime = n.Time + sustain; break; } } // initialize times for empty anchors, based on 'lrocknroll' foreach (var anchor in a.Anchors.Anchors) if (anchor.Unk3_FirstNoteTime == 0) { anchor.Unk3_FirstNoteTime = anchor.StartBeatTime; anchor.Unk4_LastNoteTime = anchor.StartBeatTime + (float)0.1; } a.Notes = new NotesSection(); a.Notes.Count = notes.Count; a.Notes.Notes = notes.ToArray(); foreach (var piter in sng.PhraseIterations.PhraseIterations) { int count = 0; int j = 0; for (; j < a.Notes.Count; j++) { // skip notes outside of a phraseiteration if (a.Notes.Notes[j].Time < piter.StartTime) continue; if (a.Notes.Notes[j].Time >= piter.NextPhraseTime) { break; } // set to next arrangement note a.Notes.Notes[j].NextIterNote = (Int16)(j + 1); // set all but first note to previous note if (count > 0) a.Notes.Notes[j].PrevIterNote = (Int16)(j - 1); ++count; } // fix last phrase note if (count > 0) a.Notes.Notes[j - 1].NextIterNote = -1; } for (int j = 1; j < a.Notes.Notes.Length; j++) { var n = a.Notes.Notes[j]; var p = a.Notes.Notes[j - 1]; int prvnote = 1; //set current + prev note + initialize prvnote variable //do not do this searching for a parent, if the previous note timestamp != current time stamp if (n.Time != p.Time) prvnote = 1; else { for (int x = 1; x < (a.Notes.Notes.Length); x++) //search up till the beginning of iteration { if (j - x < 1) //don't search past the first note in iteration { prvnote = x; x = a.Notes.Notes.Length + 2; break; // stop searching for a match we reached the beginning } var prv = a.Notes.Notes[j - x]; // get the info for the note we are checking against if (prv.Time != n.Time) { //now check the timestamp if its the same timestamp then keep looking if (prv.ChordId != -1) { //check if its a chord prvnote = x; x = a.Notes.Notes.Length + 2; break; //stop here, its a chord so don't need to check the strings } if (prv.StringIndex == n.StringIndex) { //check to see if we are looking at the same string prvnote = x; x = a.Notes.Notes.Length + 2; break; //stop here we found the same string, at a different timestamp, thats not a chord } } } } var prev = a.Notes.Notes[j - prvnote]; //this will be either the first note of piter, or the last note on the same string at previous timestamp if ((prev.NoteMask & CON.NOTE_MASK_PARENT) != 0) { n.ParentPrevNote = (short)(prev.NextIterNote - 1); n.NoteMask |= CON.NOTE_MASK_CHILD; //set the ParentPrevNote# = the matched Note#//add CHILD flag } } a.PhraseCount = xml.Phrases.Length; a.AverageNotesPerIteration = new float[a.PhraseCount]; var iter_count = new float[a.PhraseCount]; for (int j = 0; j < xml.PhraseIterations.Length; j++) { var piter = xml.PhraseIterations[j]; // using NotesInIteration2 to calculate a.AverageNotesPerIteration[piter.PhraseId] += a.NotesInIteration2[j]; ++iter_count[piter.PhraseId]; } for (int j = 0; j < iter_count.Length; j++) { if (iter_count[j] > 0) a.AverageNotesPerIteration[j] /= iter_count[j]; } // this is some kind of optimization in RS2 where they // hash all note data but their position in phrase iteration // to mark otherwise unchanged notes foreach (var n in a.Notes.Notes) { MemoryStream data = sng.CopyStruct(n); var r = new EndianBinaryReader(EndianBitConverter.Little, data); var ncopy = new Notes(); ncopy.read(r); ncopy.NextIterNote = 0; ncopy.PrevIterNote = 0; ncopy.ParentPrevNote = 0; UInt32 crc = sng.HashStruct(ncopy); if (!note_id.ContainsKey(crc)) note_id[crc] = (UInt32)note_id.Count; n.Hash = note_id[crc]; } numberNotes(sng, a.Notes.Notes); sng.Arrangements.Arrangements[i] = a; } }
/// <summary> /// Convert RS1 Song Object to RS2 Song2014 Object /// RS1 to RS2014 Mapping Method /// </summary> /// <param name="rsSong"></param> /// <param name="srcPath"></param> /// <returns>Song2014</returns> public Song2014 SongToSong2014(Song rsSong) { // Song to Song2014 Mapping Song2014 rsSong2014 = new Song2014(); // song info parsed and loaded later from // RS1 song.manifest.json file by RS1LoadFromFolder rsSong2014.Version = "7"; rsSong2014.Title = rsSong.Title; rsSong2014.Arrangement = rsSong.Arrangement; rsSong2014.Part = rsSong.Part; rsSong2014.Offset = rsSong.Offset; rsSong2014.CentOffset = "0"; rsSong2014.SongLength = rsSong.SongLength; rsSong2014.LastConversionDateTime = DateTime.Now.ToString("MM-dd-yy HH:mm"); rsSong2014.StartBeat = rsSong.Ebeats[0].Time; // if RS1 CDLC Song XML originates from EOF it may // already contain AverageTempo otherwise it gets calculated rsSong2014.AverageTempo = rsSong.AverageTempo == 0 ? AverageBPM(rsSong) : rsSong.AverageTempo; // tuning parsed from RS1 song.manifest.json file by RS1LoadFromFolder rsSong2014.Tuning = rsSong.Tuning == null ? new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 } : rsSong.Tuning; rsSong2014.Capo = 0; rsSong2014.ArtistName = rsSong.ArtistName; rsSong2014.AlbumName = rsSong.AlbumName; rsSong2014.AlbumYear = rsSong.AlbumYear; rsSong2014.CrowdSpeed = "1"; // initialize arrangement properties rsSong2014.ArrangementProperties = new SongArrangementProperties2014 { Represent = 1, StandardTuning = 1, NonStandardChords = 0, BarreChords = 0, PowerChords = 0, DropDPower = 0, OpenChords = 0, FingerPicking = 0, PickDirection = 0, DoubleStops = 0, PalmMutes = 0, Harmonics = 0, PinchHarmonics = 0, Hopo = 0, Tremolo = 0, Slides = 0, UnpitchedSlides = 0, Bends = 0, Tapping = 0, Vibrato = 0, FretHandMutes = 0, SlapPop = 0, TwoFingerPicking = 0, FifthsAndOctaves = 0, Syncopation = 0, BassPick = 0, Sustain = 0, BonusArr = 0, RouteMask = 0, PathLead = 0, PathRhythm = 0, PathBass = 0 }; // initial SWAG based on RS1 arrangement element rsSong2014.ArrangementProperties.RouteMask = rsSong.Arrangement.ToLower().Contains("lead") ? 1 : (rsSong.Arrangement.ToLower().Contains("rhythm") ? 2 : (rsSong.Arrangement.ToLower().Contains("combo") ? 2 // may not always be true : (rsSong.Arrangement.ToLower().Contains("bass") ? 4 : 1))); // but ok for now rsSong2014.ArrangementProperties.PathLead = rsSong2014.ArrangementProperties.RouteMask == 1 ? 1 : 0; rsSong2014.ArrangementProperties.PathRhythm = rsSong2014.ArrangementProperties.RouteMask == 1 ? 1 : 0; rsSong2014.ArrangementProperties.PathBass = rsSong2014.ArrangementProperties.RouteMask == 1 ? 1 : 0; // set tone defaults used to produce RS2014 CDLC rsSong2014.ToneBase = "Default"; rsSong2014.ToneA = ""; rsSong2014.ToneB = ""; rsSong2014.ToneC = ""; rsSong2014.ToneD = ""; // these elements have direct mappings rsSong2014.Phrases = rsSong.Phrases; rsSong2014.FretHandMuteTemplates = rsSong.FretHandMuteTemplates; rsSong2014.Ebeats = rsSong.Ebeats; rsSong2014.Sections = rsSong.Sections; rsSong2014.Events = rsSong.Events; // these prevent in game hanging rsSong2014.LinkedDiffs = new SongLinkedDiff[0]; rsSong2014.PhraseProperties = new SongPhraseProperty[0]; // these elements have no direct mapping, processing order is important rsSong2014 = ConvertChordTemplates(rsSong, rsSong2014); rsSong2014 = ConvertLevels(rsSong, rsSong2014); rsSong2014 = ConvertPhraseIterations(rsSong, rsSong2014); // these prevent in game hanging rsSong2014.Tones = new SongTone2014[0]; rsSong2014.NewLinkedDiff = new SongNewLinkedDiff[0]; // tested ... not the source of in game hangs // rsSong2014.TranscriptionTrack = TranscriptionTrack2014.GetDefault(); // tested ... confirmed this is a source of in game hangs // check alignment of Sections time with Ebeats first beat of measure time // TODO: use LINQ float fbomTime = 0; float nfbomTime = 0; foreach (var section in rsSong2014.Sections) { foreach (var ebeat in rsSong2014.Ebeats) { // save Ebeats first beat of measure time if (ebeat.Measure != -1) fbomTime = ebeat.Time; else nfbomTime = ebeat.Time; if (section.Name.ToLower().Contains("noguitar") && Math.Abs(ebeat.Time - section.StartTime) < 0.001) { // CRITICAL - fix Section noguitar time (matches EOF output) if (ebeat.Measure != -1) { section.StartTime = nfbomTime; Console.WriteLine("Applied fix to RS1->RS2 Section StartTime for: " + section.Name); } break; } // found a valid Section time if (ebeat.Measure != -1 && Math.Abs(ebeat.Time - section.StartTime) < 0.001) break; // fix invalid Section time if (ebeat.Measure == -1 && ebeat.Time > section.StartTime) { section.StartTime = fbomTime; Console.WriteLine("Applied fix to RS1->RS2 Section StartTime for: " + section.Name); break; } } } return rsSong2014; }
private void parseChord(Song2014 xml, Sng2014File sng, SongChord2014 chord, Notes n, Int32 chordNotesId) { n.NoteMask |= CON.NOTE_MASK_CHORD; if (chordNotesId != -1) { // there should always be a STRUM too => handshape at chord time // probably even for chordNotes which are not exported to SNG n.NoteMask |= CON.NOTE_MASK_CHORDNOTES; } if (chord.LinkNext != 0) n.NoteMask |= CON.NOTE_MASK_PARENT; if (chord.Accent != 0) n.NoteMask |= CON.NOTE_MASK_ACCENT; if (chord.FretHandMute != 0) n.NoteMask |= CON.NOTE_MASK_FRETHANDMUTE; if (chord.HighDensity != 0) n.NoteMask |= CON.NOTE_MASK_HIGHDENSITY; if (chord.Ignore != 0) n.NoteMask |= CON.NOTE_MASK_IGNORE; if (chord.PalmMute != 0) n.NoteMask |= CON.NOTE_MASK_PALMMUTE; // TODO: does not seem to have a mask or any effect // if (chord.Hopo != 0) // n.NoteMask |= ; // numbering will be set later //n.NoteFlags = CON.NOTE_FLAGS_NUMBERED; n.Time = chord.Time; n.StringIndex = unchecked((Byte)(-1)); // always -1 n.FretId = unchecked((Byte)(-1)); // anchor fret will be set later n.AnchorFretId = unchecked((Byte)(-1)); // will be overwritten n.AnchorWidth = unchecked((Byte)(-1)); n.ChordId = chord.ChordId; n.ChordNotesId = chordNotesId; n.PhraseIterationId = getPhraseIterationId(xml, n.Time, false); n.PhraseId = xml.PhraseIterations[n.PhraseIterationId].PhraseId; // these will be overwritten n.FingerPrintId[0] = -1; n.FingerPrintId[1] = -1; // these will be overwritten n.NextIterNote = -1; n.PrevIterNote = -1; // seems to be unused for chords n.ParentPrevNote = -1; n.SlideTo = unchecked((Byte)(-1)); n.SlideUnpitchTo = unchecked((Byte)(-1)); n.LeftHand = unchecked((Byte)(-1)); n.Tap = unchecked((Byte)(-1)); n.PickDirection = unchecked((Byte)(-1)); n.Slap = unchecked((Byte)(-1)); n.Pluck = unchecked((Byte)(-1)); if (chord.ChordNotes != null) { foreach (var cn in chord.ChordNotes) if (cn.Sustain > n.Sustain) n.Sustain = cn.Sustain; } if (n.Sustain > 0) n.NoteMask |= CON.NOTE_MASK_SUSTAIN; int cnt = 0; for (int str = 0; str < 6; str++) if (sng.Chords.Chords[chord.ChordId].Frets[str] != 255) ++cnt; if (cnt == 2) n.NoteMask |= CON.NOTE_MASK_DOUBLESTOP; // there are only zeros for all chords in lessons //n.Vibrato = 0; //n.MaxBend = 0; n.BendData = new BendDataSection(); n.BendData.Count = 0; n.BendData.BendData = new BendData32[n.BendData.Count]; }
private Song2014 ConvertLevels(Song rsSong, Song2014 rsSong2014) { // add levels elements var levels = new List<SongLevel2014>(); foreach (var songLevel in rsSong.Levels) { var anchors = new List<SongAnchor2014>(); var notes = new List<SongNote2014>(); var chords = new List<SongChord2014>(); var handShapes = new List<SongHandShape>(); for (int anchorIndex = 0; anchorIndex < songLevel.Anchors.Length; anchorIndex++) { var anchor = songLevel.Anchors[anchorIndex]; anchors.Add(new SongAnchor2014 { Fret = anchor.Fret, Time = anchor.Time, Width = 4 }); } for (int noteIndex = 0; noteIndex < songLevel.Notes.Length; noteIndex++) { var songNote = songLevel.Notes[noteIndex]; notes.Add(GetNoteInfo(songNote)); } for (int chordIndex = 0; chordIndex < songLevel.Chords.Length; chordIndex++) { // RS1 does not contain chordNotes so need to make them from chordtemplate List<SongNote2014> chordNotes = new List<SongNote2014>(); var zChord = songLevel.Chords[chordIndex]; var zChordId = zChord.ChordId; var zChordTemplate = rsSong.ChordTemplates[zChordId]; // this is ok no code crash //if (String.IsNullOrEmpty(zChordTemplate.ChordName)) // continue; if (zChordTemplate.Finger0 != -1) // finger > -1 is a string played chordNotes.Add(DecodeChordTemplate(zChord, 0, zChordTemplate.Fret0)); if (zChordTemplate.Finger1 != -1) chordNotes.Add(DecodeChordTemplate(zChord, 1, zChordTemplate.Fret1)); if (zChordTemplate.Finger2 != -1) chordNotes.Add(DecodeChordTemplate(zChord, 2, zChordTemplate.Fret2)); if (zChordTemplate.Finger3 != -1) chordNotes.Add(DecodeChordTemplate(zChord, 3, zChordTemplate.Fret3)); if (zChordTemplate.Finger4 != -1) chordNotes.Add(DecodeChordTemplate(zChord, 4, zChordTemplate.Fret4)); if (zChordTemplate.Finger5 != -1) chordNotes.Add(DecodeChordTemplate(zChord, 5, zChordTemplate.Fret5)); if (chordNotes.Any()) { chords.Add(new SongChord2014 { ChordId = zChord.ChordId, ChordNotes = chordNotes.ToArray(), HighDensity = zChord.HighDensity, Ignore = zChord.Ignore, Strum = zChord.Strum, Time = zChord.Time }); // add chordNotes to songNotes for compatibility notes.AddRange(chordNotes); } } // tested ... not the source of game hangs // get rid of duplicate notes if any // notes = notes.Distinct().ToList(); for (int shapeIndex = 0; shapeIndex < songLevel.HandShapes.Length; shapeIndex++) { var handshape = songLevel.HandShapes[shapeIndex]; handShapes.Add(new SongHandShape { ChordId = handshape.ChordId, EndTime = handshape.EndTime, StartTime = handshape.StartTime }); } levels.Add(new SongLevel2014 { Anchors = anchors.ToArray(), Chords = chords.ToArray(), Difficulty = songLevel.Difficulty, HandShapes = handShapes.ToArray(), Notes = notes.ToArray() }); } rsSong2014.Levels = levels.ToArray(); return rsSong2014; }
private void parseChordNotes(Song2014 xml, Sng2014File sng) { sng.ChordNotes = new ChordNotesSection(); sng.ChordNotes.ChordNotes = cns.ToArray(); sng.ChordNotes.Count = sng.ChordNotes.ChordNotes.Length; }
/// <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; }
private void parseChords(Song2014 xml, Sng2014File sng, Int16[] tuning, bool bass) { sng.Chords = new ChordSection(); sng.Chords.Count = xml.ChordTemplates.Length; sng.Chords.Chords = new Chord[sng.Chords.Count]; for (int i = 0; i < sng.Chords.Count; i++) { var chord = xml.ChordTemplates[i]; var c = new Chord(); // TODO: skip if DisplayName == null if (chord.DisplayName.EndsWith("arp")) c.Mask |= CON.CHORD_MASK_ARPEGGIO; else if (chord.DisplayName.EndsWith("nop")) c.Mask |= CON.CHORD_MASK_NOP; c.Frets[0] = (Byte)chord.Fret0; c.Frets[1] = (Byte)chord.Fret1; c.Frets[2] = (Byte)chord.Fret2; c.Frets[3] = (Byte)chord.Fret3; c.Frets[4] = (Byte)chord.Fret4; c.Frets[5] = (Byte)chord.Fret5; c.Fingers[0] = (Byte)chord.Finger0; c.Fingers[1] = (Byte)chord.Finger1; c.Fingers[2] = (Byte)chord.Finger2; c.Fingers[3] = (Byte)chord.Finger3; c.Fingers[4] = (Byte)chord.Finger4; c.Fingers[5] = (Byte)chord.Finger5; for (Byte s = 0; s < 6; s++) c.Notes[s] = GetMidiNote(tuning, s, c.Frets[s], bass, xml.Capo, template: true); readString(chord.ChordName, c.Name); sng.Chords.Chords[i] = c; } }