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;
            this.TuningStrings = tuning.Tuning;

            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;
        }
        private Arrangement(Attributes2014 attr, Sng2014File song, Guid id)
        {
            this.ArrangementSort = attr.ArrangementSort;
            this.Sng2014 = song;
            this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName);
            this.ScrollSpeed = 20;
            this.Id = id;
            this.MasterId = ArrangementType == Sng.ArrangementType.Vocal ? 1 : RandomGenerator.NextInt();

            if (this.ArrangementType == ArrangementType.Vocal)
            {
                this.Tones = new List<Tone2014>();
            } else
            {
                ParseTuning(this, attr);
                ParseTones(this, attr);
            }
        }
        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();
                tone.Id = toneSection.Tones[i].ToneId;
                tone.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 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 = 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 = (sngData.Metadata.CapoFretId >= 0) ? sngData.Metadata.CapoFretId : (byte)0;
                LastConversionDateTime = sngData.Metadata.LastConversionDateTime.ToNullTerminatedAscii();
            }

            Tones = (attr != null) ? SongTone2014.Parse(sngData.Tones, attr) : SongTone2014.Parse(sngData.Tones);
            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];
        }
        private static void GenerateRS2014SongPsarc(MemoryStream output, DLCPackageData info, Platform platform)
        {
            var dlcName = info.Name.ToLower();

            {
                var 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 ddsfiles)
                        packPsarc.AddEntry(String.Format("gfxassets/album_art/album_{0}_{1}.dds", dlcName, dds.sizeX), new FileStream(dds.destinationFile, FileMode.Open, FileAccess.Read, FileShare.Read));

                    //Lyrics Font Texture
                    if (File.Exists(info.LyricsTex))
                        packPsarc.AddEntry(String.Format("assets/ui/lyrics/{0}/lyrics_{0}.dds", dlcName), new FileStream(info.LyricsTex, 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);
                            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 = (info.PreviewVolume != null) ? (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(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)
                        {
                            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 != Sng.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);

                            var jsonPathPC = "manifests/songs_dlc_{0}/{0}_{1}.json";
                            var 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);
                        }

                        // SHOWLIGHT
                        Showlights showlight = new Showlights(info);
                        showlight.Serialize(showlightStream);
                        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);
                    }
                } catch (Exception ex) {
                    throw ex;
                } finally {
                    // Dispose all objects
                    if (soundStream != null)
                        soundStream.Dispose();
                    if (soundPreviewStream != null)
                        soundPreviewStream.Dispose();
                    if (rsenumerableRootStream != null)
                        rsenumerableRootStream.Dispose();
                    if (rsenumerableSongStream != null)
                        rsenumerableSongStream.Dispose();
                    DeleteTmpFiles(TMPFILES_SNG);
                    DeleteTmpFiles(TMPFILES_ART);
                }
            }
        }
        private static void ParseTuning(Arrangement dest, Attributes2014 attr)
        {
            bool isBass = false;
            TuningDefinition tuning = null;
            switch (dest.Name)
            {
                case ArrangementName.Bass:
                    tuning = TuningDefinitionRepository.Instance().SelectForBass(attr.Tuning, GameVersion.RS2014);
                    isBass = true;
                    break;
                case ArrangementName.Vocals:
                    break;
                default:
                    tuning = TuningDefinitionRepository.Instance().Select(attr.Tuning, GameVersion.RS2014);
                    break;

            }

            if (tuning == null)
            {
                tuning = new TuningDefinition();
                tuning.UIName = tuning.Name = TuningDefinition.NameFromStrings(attr.Tuning, isBass);
                tuning.Custom = true;
                tuning.GameVersion = GameVersion.RS2014;
                tuning.Tuning = attr.Tuning;
                TuningDefinitionRepository.Instance().Add(tuning, true);
            }
            dest.Tuning = tuning.UIName;
            dest.TuningStrings = tuning.Tuning;

            if (attr.CentOffset != null)
                dest.TuningPitch = attr.CentOffset.Cents2Frequency();
        }
 private static void ParseTones(Arrangement dest, Attributes2014 attr)
 {
     dest.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10);
     dest.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick;
     dest.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask;
     dest.BonusArr = attr.ArrangementProperties.BonusArr == 1;
     dest.ToneBase = attr.Tone_Base;
     dest.ToneMultiplayer = attr.Tone_Multiplayer;
     dest.ToneA = attr.Tone_A;
     dest.ToneB = attr.Tone_B;
     dest.ToneC = attr.Tone_C;
     dest.ToneD = attr.Tone_D;
     dest.Tones = attr.Tones.ToList();
 }
        public static Arrangement Read(Attributes2014 attr, Platform platform, Guid id, string filename, Stream data = null)
        {
            Arrangement result = null;
            using (var str = data ?? File.OpenRead(filename))
            {
                switch (Path.GetExtension(filename))
                {
                    case ".xml":
                        Sng2014File xml = null;
                        if (((ArrangementName)attr.ArrangementType) == ArrangementName.Vocals)
                            xml = Sng2014FileWriter.ReadVocals(data);
                        else
                            xml = Sng2014File.ConvertXML(str);
                        result = new Arrangement(attr, xml, id);
                        break;
                    case ".sng":
                        result = new Arrangement(attr, Sng2014File.ReadSng(str, platform), id);
                        break;
                    default:
                        throw new Exception("Unknown file type: " + filename);
                }
                result._songFilename = filename;

            }
            return result;
        }
 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);
 }