예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
            }
        }
예제 #6
0
        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;
            }
        }
예제 #9
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);
 }
예제 #16
0
        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);
        }
예제 #17
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;
        }
예제 #19
0
        // 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);
            }
        }
예제 #21
0
        /// <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);
        }
예제 #22
0
        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);
                }
            }
        }
예제 #24
0
        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();
        }
예제 #28
0
        // 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);
        }