Beispiel #1
0
        private void WritePropertyInternal(string smPropertyName, object value)
        {
            if (value == null)
            {
                WritePropertyInternal(smPropertyName, "");
            }
            else if (value is List <string> valAsList)
            {
                StreamWriter.Write($"{MSDFile.ValueStartMarker}{smPropertyName}{MSDFile.ParamMarker}");
                var first = true;
                foreach (var entry in valAsList)
                {
                    if (!first)
                    {
                        StreamWriter.Write(MSDFile.ParamMarker);
                    }
                    if (!string.IsNullOrEmpty(entry))
                    {
                        StreamWriter.Write(MSDFile.Escape(entry));
                    }
                    first = false;
                }

                StreamWriter.WriteLine(MSDFile.ValueEndMarker);
            }
            else if (value is double d)
            {
                WritePropertyInternal(smPropertyName, d.ToString(SMCommon.SMDoubleFormat));
            }
            else
            {
                WritePropertyInternal(smPropertyName, value.ToString());
            }
        }
Beispiel #2
0
        /// <summary>
        /// Write the given Chart.
        /// </summary>
        /// <param name="chart">Chart to write.</param>
        private void WriteChart(Chart chart)
        {
            // We need a valid ChartType. If we don't have one, don't write the Chart.
            // Logging about ChartType errors performed in DetermineChartDifficultyTypes.
            if (!TryGetChartType(chart, out var chartType))
            {
                return;
            }

            var charTypeStr         = chartType.ToString().Replace('_', '-');
            var chartDifficultyType = GetChartDifficultyTypeString(chart);
            var radarValues         = GetRadarValues(chart);

            // Write chart header.
            StreamWriter.WriteLine();
            StreamWriter.WriteLine($"//---------------{charTypeStr} - {MSDFile.Escape(chart.Description ?? "")}----------------");
            WriteChartNotesValueStart(chart);
            StreamWriter.WriteLine($"     {charTypeStr}{MSDFile.ParamMarker}");
            StreamWriter.WriteLine($"     {MSDFile.Escape(chart.Description)}{MSDFile.ParamMarker}");
            StreamWriter.WriteLine($"     {chartDifficultyType}{MSDFile.ParamMarker}");
            StreamWriter.WriteLine($"     {(int)chart.DifficultyRating}{MSDFile.ParamMarker}");
            StreamWriter.WriteLine($"     {radarValues}{MSDFile.ParamMarker}");

            // Write all the notes.
            WriteChartNotes(chart);

            // Mark the chart as complete.
            StreamWriter.WriteLine(MSDFile.ValueEndMarker);
        }
Beispiel #3
0
        /// <summary>
        /// Load the sm file specified by the provided file path.
        /// </summary>
        public override async Task <Song> Load()
        {
            // Load the file as an MSDFile.
            var msdFile = new MSDFile();
            var result  = await msdFile.Load(FilePath);

            if (!result)
            {
                Logger.Error("Failed to load MSD File.");
                return(null);
            }

            var tempos = new Dictionary <double, double>();
            var stops  = new Dictionary <double, double>();

            var song = new Song();

            song.SourceType = FileFormatType.SM;

            var propertyParsers = new Dictionary <string, PropertyParser>()
            {
                [SMCommon.TagTitle]            = new PropertyToSongPropertyParser(SMCommon.TagTitle, nameof(Song.Title), song),
                [SMCommon.TagSubtitle]         = new PropertyToSongPropertyParser(SMCommon.TagSubtitle, nameof(Song.SubTitle), song),
                [SMCommon.TagArtist]           = new PropertyToSongPropertyParser(SMCommon.TagArtist, nameof(Song.Artist), song),
                [SMCommon.TagTitleTranslit]    = new PropertyToSongPropertyParser(SMCommon.TagTitleTranslit, nameof(Song.TitleTransliteration), song),
                [SMCommon.TagSubtitleTranslit] = new PropertyToSongPropertyParser(SMCommon.TagSubtitleTranslit, nameof(Song.SubTitleTransliteration), song),
                [SMCommon.TagArtistTranslit]   = new PropertyToSongPropertyParser(SMCommon.TagArtistTranslit, nameof(Song.ArtistTransliteration), song),
                [SMCommon.TagGenre]            = new PropertyToSongPropertyParser(SMCommon.TagGenre, nameof(Song.Genre), song),
                [SMCommon.TagCredit]           = new PropertyToSourceExtrasParser <string>(SMCommon.TagCredit, song.Extras),
                [SMCommon.TagBanner]           = new PropertyToSongPropertyParser(SMCommon.TagBanner, nameof(Song.SongSelectImage), song),
                [SMCommon.TagBackground]       = new PropertyToSourceExtrasParser <string>(SMCommon.TagBackground, song.Extras),
                [SMCommon.TagLyricsPath]       = new PropertyToSourceExtrasParser <string>(SMCommon.TagLyricsPath, song.Extras),
                [SMCommon.TagCDTitle]          = new PropertyToSourceExtrasParser <string>(SMCommon.TagCDTitle, song.Extras),
                [SMCommon.TagMusic]            = new PropertyToSourceExtrasParser <string>(SMCommon.TagMusic, song.Extras),
                [SMCommon.TagOffset]           = new PropertyToSourceExtrasParser <double>(SMCommon.TagOffset, song.Extras),
                [SMCommon.TagBPMs]             = new CSVListAtTimePropertyParser <double>(SMCommon.TagBPMs, tempos, song.Extras, SMCommon.TagFumenRawBpmsStr),
                [SMCommon.TagStops]            = new CSVListAtTimePropertyParser <double>(SMCommon.TagStops, stops, song.Extras, SMCommon.TagFumenRawStopsStr),
                [SMCommon.TagFreezes]          = new CSVListAtTimePropertyParser <double>(SMCommon.TagFreezes, stops),
                [SMCommon.TagDelays]           = new PropertyToSourceExtrasParser <string>(SMCommon.TagDelays, song.Extras),
                // Removed, see https://github.com/stepmania/stepmania/issues/9
                [SMCommon.TagTimeSignatures]  = new PropertyToSourceExtrasParser <string>(SMCommon.TagTimeSignatures, song.Extras),
                [SMCommon.TagTickCounts]      = new PropertyToSourceExtrasParser <string>(SMCommon.TagTickCounts, song.Extras),
                [SMCommon.TagInstrumentTrack] = new PropertyToSourceExtrasParser <string>(SMCommon.TagInstrumentTrack, song.Extras),
                [SMCommon.TagSampleStart]     = new PropertyToSongPropertyParser(SMCommon.TagSampleStart, nameof(Song.PreviewSampleStart), song),
                [SMCommon.TagSampleLength]    = new PropertyToSongPropertyParser(SMCommon.TagSampleLength, nameof(Song.PreviewSampleLength), song),
                [SMCommon.TagDisplayBPM]      = new ListPropertyToSourceExtrasParser <string>(SMCommon.TagDisplayBPM, song.Extras),
                [SMCommon.TagSelectable]      = new PropertyToSourceExtrasParser <string>(SMCommon.TagSelectable, song.Extras),
                [SMCommon.TagAnimations]      = new PropertyToSourceExtrasParser <string>(SMCommon.TagAnimations, song.Extras),
                [SMCommon.TagBGChanges]       = new PropertyToSourceExtrasParser <string>(SMCommon.TagBGChanges, song.Extras),
                [SMCommon.TagBGChanges1]      = new PropertyToSourceExtrasParser <string>(SMCommon.TagBGChanges1, song.Extras),
                [SMCommon.TagBGChanges2]      = new PropertyToSourceExtrasParser <string>(SMCommon.TagBGChanges2, song.Extras),
                [SMCommon.TagFGChanges]       = new PropertyToSourceExtrasParser <string>(SMCommon.TagFGChanges, song.Extras),
                // TODO: Parse Keysounds properly.
                [SMCommon.TagKeySounds]    = new PropertyToSourceExtrasParser <string>(SMCommon.TagKeySounds, song.Extras),
                [SMCommon.TagAttacks]      = new ListPropertyToSourceExtrasParser <string>(SMCommon.TagAttacks, song.Extras),
                [SMCommon.TagNotes]        = new SongNotesPropertyParser(SMCommon.TagNotes, song),
                [SMCommon.TagNotes2]       = new SongNotesPropertyParser(SMCommon.TagNotes2, song),
                [SMCommon.TagLastBeatHint] = new PropertyToSourceExtrasParser <string>(SMCommon.TagLastBeatHint, song.Extras),
            };

            foreach (var kvp in propertyParsers)
            {
                kvp.Value.SetLogger(Logger);
            }

            // Parse all Values from the MSDFile.
            foreach (var value in msdFile.Values)
            {
                if (propertyParsers.TryGetValue(value.Params[0]?.ToUpper() ?? "", out var propertyParser))
                {
                    propertyParser.Parse(value);
                }
            }

            // Insert stop and tempo change events.
            foreach (var chart in song.Charts)
            {
                SMCommon.AddStops(stops, chart);
                SMCommon.AddTempos(tempos, chart);
            }

            // Sort events.
            foreach (var chart in song.Charts)
            {
                chart.Layers[0].Events.Sort(new SMCommon.SMEventComparer());
            }

            song.GenreTransliteration = song.Genre;

            var chartOffset = 0.0;

            if (song.Extras.TryGetSourceExtra(SMCommon.TagOffset, out object offsetObj))
            {
                chartOffset = (double)offsetObj;
            }

            var chartMusicFile = "";

            if (song.Extras.TryGetSourceExtra(SMCommon.TagMusic, out object chartMusicFileObj))
            {
                chartMusicFile = (string)chartMusicFileObj;
            }

            var chartAuthor = "";

            if (song.Extras.TryGetSourceExtra(SMCommon.TagCredit, out object chartAuthorObj))
            {
                chartAuthor = (string)chartAuthorObj;
            }

            var chartDisplayTempo = SMCommon.GetDisplayBPMStringFromSourceExtrasList(song.Extras, tempos);

            foreach (var chart in song.Charts)
            {
                chart.MusicFile            = chartMusicFile;
                chart.ChartOffsetFromMusic = chartOffset;
                chart.Tempo  = chartDisplayTempo;
                chart.Artist = song.Artist;
                chart.ArtistTransliteration = song.ArtistTransliteration;
                chart.Genre = song.Genre;
                chart.GenreTransliteration = song.GenreTransliteration;
                chart.Author = chartAuthor;
                SMCommon.SetEventTimeMicros(chart);
            }

            return(song);
        }
Beispiel #4
0
        /// <summary>
        /// Load the ssc file specified by the provided file path.
        /// </summary>
        public override async Task <Song> Load()
        {
            // Load the file as an MSDFile.
            var msdFile = new MSDFile();
            var result  = await msdFile.Load(FilePath);

            if (!result)
            {
                Logger.Error("Failed to load MSD File.");
                return(null);
            }

            var song = new Song();

            song.SourceType = FileFormatType.SSC;
            var songTempos          = new Dictionary <double, double>();
            var songStops           = new Dictionary <double, double>();
            var songPropertyParsers = GetSongPropertyParsers(song, songTempos, songStops);

            Dictionary <string, PropertyParser> chartPropertyParsers = null;
            Chart activeChart = null;
            Dictionary <double, double> activeChartTempos = null;
            Dictionary <double, double> activeChartStops  = null;

            // Parse all Values from the MSDFile.
            foreach (var value in msdFile.Values)
            {
                var valueStr = value.Params[0]?.ToUpper() ?? "";

                // Starting a new Chart.
                if (valueStr == SMCommon.TagNoteData)
                {
                    // Final cleanup on the Song
                    if (activeChart == null)
                    {
                        song.GenreTransliteration = song.Genre;
                    }

                    // Add the previous Chart.
                    if (activeChart != null)
                    {
                        FinalizeChartAndAddToSong(
                            activeChart,
                            activeChartTempos,
                            activeChartStops,
                            song,
                            songTempos,
                            songStops);
                    }

                    // Set up a new Chart.
                    activeChart = new Chart();
                    activeChart.Layers.Add(new Layer());
                    // Add a 4/4 Time Signature.
                    activeChart.Layers[0].Events.Add(new TimeSignature(new Fraction(SMCommon.NumBeatsPerMeasure, SMCommon.NumBeatsPerMeasure))
                    {
                        Position = new MetricPosition()
                    });

                    activeChartTempos    = new Dictionary <double, double>();
                    activeChartStops     = new Dictionary <double, double>();
                    chartPropertyParsers = GetChartPropertyParsers(activeChart, activeChartTempos, activeChartStops);
                    continue;
                }

                // Parse as a Chart property.
                if (activeChart != null)
                {
                    // Matches Stepmania logic. If any timing value is present, assume all timing values must be from the
                    // Chart and not the Song.
                    if (ChartTimingDataTags.Contains(valueStr))
                    {
                        activeChart.Extras.AddSourceExtra(SMCommon.TagFumenChartUsesOwnTimingData, true, true);
                    }

                    if (chartPropertyParsers.TryGetValue(valueStr, out var propertyParser))
                    {
                        propertyParser.Parse(value);
                    }
                }

                // Parse as a Song property.
                else
                {
                    if (songPropertyParsers.TryGetValue(valueStr, out var propertyParser))
                    {
                        propertyParser.Parse(value);
                    }
                }
            }

            // Add the final Chart.
            if (activeChart != null)
            {
                FinalizeChartAndAddToSong(
                    activeChart,
                    activeChartTempos,
                    activeChartStops,
                    song,
                    songTempos,
                    songStops);
            }

            return(song);
        }
Beispiel #5
0
 private void WritePropertyInternal(string smPropertyName, string value)
 {
     if (string.IsNullOrEmpty(value))
     {
         StreamWriter.WriteLine(
             $"{MSDFile.ValueStartMarker}{smPropertyName}{MSDFile.ParamMarker}{MSDFile.ValueEndMarker}");
     }
     else
     {
         StreamWriter.WriteLine(
             $"{MSDFile.ValueStartMarker}{smPropertyName}{MSDFile.ParamMarker}{MSDFile.Escape(value)}{MSDFile.ValueEndMarker}");
     }
 }