/// <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); }
private void FinalizeChartAndAddToSong( Chart chart, Dictionary <double, double> chartTempos, Dictionary <double, double> chartStops, Song song, Dictionary <double, double> songTempos, Dictionary <double, double> songStops) { // Do not add this Chart if we failed to parse the type. if (string.IsNullOrEmpty(chart.Type)) { return; } var useChartTimingData = false; if (chart.Extras.TryGetSourceExtra(SMCommon.TagFumenChartUsesOwnTimingData, out object useTimingDataObject)) { if (useTimingDataObject is bool b) { useChartTimingData = b; } } // Insert stop and tempo change events. SMCommon.AddStops(useChartTimingData ? chartStops : songStops, chart); SMCommon.AddTempos(useChartTimingData ? chartTempos : songTempos, chart); // Sort events. chart.Layers[0].Events.Sort(new SMCommon.SMEventComparer()); // Copy Song information over missing Chart information. if (string.IsNullOrEmpty(chart.MusicFile)) { var chartMusicFile = ""; if (song.Extras.TryGetSourceExtra(SMCommon.TagMusic, out object chartMusicFileObj)) { chartMusicFile = (string)chartMusicFileObj; } if (!string.IsNullOrEmpty(chartMusicFile)) { chart.MusicFile = chartMusicFile; } } if (string.IsNullOrEmpty(chart.Author)) { var chartAuthor = ""; if (song.Extras.TryGetSourceExtra(SMCommon.TagCredit, out object chartAuthorObj)) { chartAuthor = (string)chartAuthorObj; } if (!string.IsNullOrEmpty(chartAuthor)) { chart.Author = chartAuthor; } } if (string.IsNullOrEmpty(chart.Artist) && !string.IsNullOrEmpty(song.Artist)) { chart.Artist = song.Artist; } if (string.IsNullOrEmpty(chart.ArtistTransliteration) && !string.IsNullOrEmpty(song.ArtistTransliteration)) { chart.ArtistTransliteration = song.ArtistTransliteration; } if (string.IsNullOrEmpty(chart.Genre) && !string.IsNullOrEmpty(song.Genre)) { chart.Genre = song.Genre; } if (string.IsNullOrEmpty(chart.GenreTransliteration) && !string.IsNullOrEmpty(song.GenreTransliteration)) { chart.GenreTransliteration = song.GenreTransliteration; } if (!chart.Extras.TryGetSourceExtra(SMCommon.TagOffset, out object _) && song.Extras.TryGetSourceExtra(SMCommon.TagOffset, out object offsetObj)) { chart.ChartOffsetFromMusic = (double)offsetObj; } if (!chart.Extras.TryGetSourceExtra(SMCommon.TagDisplayBPM, out object _)) { chart.Tempo = SMCommon.GetDisplayBPMStringFromSourceExtrasList( song.Extras, useChartTimingData ? chartTempos : songTempos); } SMCommon.SetEventTimeMicros(chart); // Add the Chart. song.Charts.Add(chart); }