diff --git a/Charts/SongIni.cs b/Charts/SongIni.cs
new file mode 100644
index 0000000..97e2129
--- /dev/null
+++ b/Charts/SongIni.cs
@@ -0,0 +1,749 @@
+using System;
+
+namespace SabreTools.Models.Charts
+{
+ ///
+ /// [song]/[Song]
+ internal class SongIni
+ {
+ #region Song/Chart Metadata
+
+ ///
+ /// Title of the song.
+ ///
+ /// name
+#if NET48
+ public string Name { get; set; }
+#else
+ public string? Name { get; set; }
+#endif
+
+ ///
+ /// Artist(s) or band(s) behind the song.
+ ///
+ /// artist
+#if NET48
+ public string Artist { get; set; }
+#else
+ public string? Artist { get; set; }
+#endif
+
+ ///
+ /// Title of the album the song is featured in.
+ ///
+ /// album
+#if NET48
+ public string Album { get; set; }
+#else
+ public string? Album { get; set; }
+#endif
+
+ ///
+ /// Genre of the song.
+ ///
+ /// genre
+#if NET48
+ public string Genre { get; set; }
+#else
+ public string? Genre { get; set; }
+#endif
+
+ ///
+ /// Sub-genre for the song.
+ ///
+ /// sub_genre
+#if NET48
+ public string SubGenre { get; set; }
+#else
+ public string? SubGenre { get; set; }
+#endif
+
+ ///
+ /// Year of the song’s release.
+ ///
+ /// year
+#if NET48
+ public string Year { get; set; }
+#else
+ public string? Year { get; set; }
+#endif
+
+ ///
+ /// Community member responsible for charting the song.
+ ///
+ /// charter, frets
+#if NET48
+ public string Charter { get; set; }
+#else
+ public string? Charter { get; set; }
+#endif
+
+ ///
+ /// Version number for the song.
+ ///
+ /// version
+ public long? Version { get; set; }
+
+ ///
+ /// Track number of the song within the album it's from.
+ ///
+ /// album_track, track
+ public long? AlbumTrack { get; set; }
+
+ ///
+ /// Track number of the song within the playlist/setlist it's from.
+ ///
+ /// playlist_track
+ public long? PlaylistTrack { get; set; }
+
+ ///
+ /// Length of the song's audio in milliseconds.
+ ///
+ /// song_length
+ public long? SongLength { get; set; }
+
+ ///
+ /// Timestamp in milliseconds where the song preview starts.
+ ///
+ /// preview_start_time
+ public long? PreviewStartTime { get; set; }
+
+ ///
+ /// Timestamp in milliseconds that the preview should stop at.
+ ///
+ /// preview_end_time
+ public long? PreviewEndTime { get; set; }
+
+ ///
+ /// Flavor text for this song, usually shown after picking the song or during loading.
+ ///
+ /// loading_phrase
+#if NET48
+ public string LoadingPhrase { get; set; }
+#else
+ public string? LoadingPhrase { get; set; }
+#endif
+
+ #endregion
+
+ #region Song/Chart Metadata (Game-Specific)
+
+ ///
+ /// (FoFiX) Hex color to use in the song screen for the cassette.
+ ///
+ /// cassettecolor
+#if NET48
+ public string CassetteColor { get; set; }
+#else
+ public string? CassetteColor { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) Miscellaneous tags for the chart.
+ /// Only known valid value is `cover`.
+ ///
+ /// tags
+#if NET48
+ public string Tags { get; set; }
+#else
+ public string? Tags { get; set; }
+#endif
+
+ ///
+ /// (PS) Two timestamps in milliseconds for preview start and end time.
+ /// Example: `55000 85000`
+ ///
+ /// preview
+#if NET48
+ public long[] Preview { get; set; }
+#else
+ public long[]? Preview { get; set; }
+#endif
+
+ ///
+ /// (CH) Playlist that the song should show up in.
+ ///
+ /// playlist
+#if NET48
+ public string Playlist { get; set; }
+#else
+ public string? Playlist { get; set; }
+#endif
+
+ ///
+ /// (CH) Sub-playlist that the song should show up in.
+ ///
+ /// sub_playlist
+#if NET48
+ public string SubPlaylist { get; set; }
+#else
+ public string? SubPlaylist { get; set; }
+#endif
+
+ ///
+ /// (CH) Indicates if this song is a modchart.
+ /// Meant for sorting purposes only.
+ ///
+ /// modchart
+ public bool? Modchart { get; set; }
+
+ ///
+ /// (CH) Indicates if the song has lyrics or not.
+ /// Meant for sorting purposes only.
+ ///
+ /// lyrics
+ public bool? Lyrics { get; set; }
+
+ #endregion
+
+ #region Track Difficulties
+
+ ///
+ /// Overall difficulty of the song.
+ ///
+ /// diff_band
+ public long? DiffBand { get; set; }
+
+ ///
+ /// Difficulty of the Lead Guitar track.
+ ///
+ /// diff_guitar
+ public long? DiffGuitar { get; set; }
+
+ ///
+ /// Difficulty of the 6-Fret Lead track.
+ ///
+ /// diff_guitarghl
+ public long? DiffGuitarGHL { get; set; }
+
+ ///
+ /// Difficulty of the Guitar Co-op track.
+ ///
+ /// diff_guitar_coop
+ public long? DiffGuitarCoop { get; set; }
+
+ ///
+ /// Difficulty of the 6-Fret Guitar Co-op track.
+ ///
+ /// diff_guitar_coop_ghl
+ public long? DiffGuitarCoopGHL { get; set; }
+
+ ///
+ /// Difficulty of the Pro Guitar track.
+ ///
+ /// diff_guitar_real
+ public long? DiffGuitarReal { get; set; }
+
+ ///
+ /// Difficulty of the Pro Guitar 22-fret track.
+ ///
+ /// diff_guitar_real_22
+ public long? DiffGuitarReal22 { get; set; }
+
+ ///
+ /// Difficulty of the Rhythm Guitar track.
+ ///
+ /// diff_rhythm
+ public long? DiffRhythm { get; set; }
+
+ ///
+ /// Difficulty of the 6-Fret Rhythm Guitar track.
+ ///
+ /// diff_rhythm_ghl
+ public long? DiffRhythmGHL { get; set; }
+
+ ///
+ /// Difficulty of the Bass Guitar track.
+ ///
+ /// diff_bass
+ public long? DiffBass { get; set; }
+
+ ///
+ /// Difficulty of the 6-Fret Bass track.
+ ///
+ /// diff_bassghl
+ public long? DiffBassGHL { get; set; }
+
+ ///
+ /// Difficulty of the Pro Bass track.
+ ///
+ /// diff_bass_real
+ public long? DiffBassReal { get; set; }
+
+ ///
+ /// Difficulty of the Pro Bass 22-fret track.
+ ///
+ /// diff_bass_real_22
+ public long? DiffBassReal22 { get; set; }
+
+ ///
+ /// Difficulty of the Drums track.
+ ///
+ /// diff_drums
+ public long? DiffDrums { get; set; }
+
+ ///
+ /// Difficulty of the Pro Drums track.
+ ///
+ /// diff_drums_real
+ public long? DiffDrumsReal { get; set; }
+
+ ///
+ /// Difficulty of the Drums Real track.
+ ///
+ /// diff_drums_real_ps
+ public long? DiffDrumsRealPS { get; set; }
+
+ ///
+ /// Difficulty of the Keys track.
+ ///
+ /// diff_keys
+ public long? DiffKeys { get; set; }
+
+ ///
+ /// Difficulty of the Pro Keys track.
+ ///
+ /// diff_keys_real
+ public long? DiffKeysReal { get; set; }
+
+ ///
+ /// Difficulty of the Keys Real track.
+ ///
+ /// diff_keys_real_ps
+ public long? DiffKeysRealPS { get; set; }
+
+ ///
+ /// Difficulty of the Vocals track.
+ ///
+ /// diff_vocals
+ public long? DiffVocals { get; set; }
+
+ ///
+ /// Difficulty of the Harmonies track.
+ ///
+ /// diff_vocals_harm
+ public long? DiffVocalsHarm { get; set; }
+
+ ///
+ /// Difficulty of the Dance track.
+ ///
+ /// diff_dance
+ public long? DiffDance { get; set; }
+
+ #endregion
+
+ #region Chart Properties
+
+ ///
+ /// Forces the Drums track to be Pro Drums.
+ ///
+ /// pro_drums, pro_drum (FoFiX)
+ public bool? ProDrums { get; set; }
+
+ ///
+ /// Forces the Drums track to be 5-lane.
+ ///
+ /// five_lane_drums
+ public bool? FiveLaneDrums { get; set; }
+
+ ///
+ /// Specifies a voice type for the singer (either "male" or "female").
+ ///
+ /// vocal_gender
+#if NET48
+ public string VocalGender { get; set; }
+#else
+ public string? VocalGender { get; set; }
+#endif
+
+ ///
+ /// Specifies a tuning for 17-fret Pro Guitar.
+ ///
+ /// real_guitar_tuning
+#if NET48
+ public string RealGuitarTuning { get; set; }
+#else
+ public string? RealGuitarTuning { get; set; }
+#endif
+
+ ///
+ /// Specifies a tuning for 22-fret Pro Guitar.
+ ///
+ /// real_guitar_22_tuning
+#if NET48
+ public string RealGuitar22Tuning { get; set; }
+#else
+ public string? RealGuitar22Tuning { get; set; }
+#endif
+
+ ///
+ /// Specifies a tuning for 17-fret Pro Bass.
+ ///
+ /// real_bass_tuning
+#if NET48
+ public string RealBassTuning { get; set; }
+#else
+ public string? RealBassTuning { get; set; }
+#endif
+
+ ///
+ /// Specifies a tuning for 22-fret Pro Bass.
+ ///
+ /// real_bass_22_tuning
+#if NET48
+ public string RealBass22Tuning { get; set; }
+#else
+ public string? RealBass22Tuning { get; set; }
+#endif
+
+ ///
+ /// Specifies the number of lanes for the right hand in Real Keys.
+ ///
+ /// real_keys_lane_count_right
+ public long? RealKeysLaneCountRight { get; set; }
+
+ ///
+ /// Specifies the number of lanes for the left hand in Real Keys.
+ ///
+ /// real_keys_lane_count_left
+ public long? RealKeysLaneCountLeft { get; set; }
+
+ ///
+ /// Delays the chart relative to the audio by the specified number of milliseconds.
+ /// Higher = later notes. Can be negative.
+ ///
+ /// delay
+ [Obsolete]
+ public long? Delay { get; set; }
+
+ ///
+ /// Overrides the default sustain cutoff threshold with a specified value in ticks.
+ ///
+ /// sustain_cutoff_threshold
+ [Obsolete]
+ public long? SustainCutoffThreshold { get; set; }
+
+ ///
+ /// Overrides the default HOPO threshold with a specified value in ticks.
+ ///
+ /// hopo_frequency
+ [Obsolete]
+ public long? HopoFrequency { get; set; }
+
+ ///
+ /// Sets the HOPO threshold to be a 1/8th step.
+ ///
+ /// eighthnote_hopo
+ [Obsolete]
+ public bool? EighthNoteHopo { get; set; }
+
+ ///
+ /// Overrides the .mid note number for Star Power on 5-Fret Guitar.
+ /// Valid values are 103 and 116.
+ ///
+ /// multiplier_note, star_power_note (PS)
+ [Obsolete]
+ public long? MultiplierNote { get; set; }
+
+ #endregion
+
+ #region Chart Properties (Game-Specific)
+
+ ///
+ /// (PS) Sets 5 to 4 Lane Drums Fallback Note
+ ///
+ /// drum_fallback_blue
+ public bool? DrumFallbackBlue { get; set; }
+
+ ///
+ /// (FoFiX) Marks a song as a tutorial and hides it from Quickplay.
+ ///
+ /// tutorial
+ public bool? Tutorial { get; set; }
+
+ ///
+ /// (FoFiX) Marks a song as a boss battle.
+ ///
+ /// boss_battle
+ public bool? BossBattle { get; set; }
+
+ ///
+ /// (FoFiX) Overrides the natural HOPO threshold using numbers from 0 to 5.
+ ///
+ /// hopofreq
+ [Obsolete]
+ public long? HopoFreq { get; set; }
+
+ ///
+ /// (FoFiX) Sets the "early hit window" size.
+ /// Valid values are "none", "half", or "full".
+ ///
+ /// early_hit_window_size
+#if NET48
+ public string EarlyHitWindowSize { get; set; }
+#else
+ public string? EarlyHitWindowSize { get; set; }
+#endif
+
+ ///
+ /// (CH) Sets whether or not end events in the chart will be respected.
+ ///
+ /// end_events
+ public bool? EndEvents { get; set; }
+
+ ///
+ /// (PS) Enables .mid SysEx events for guitar sliders/tap notes.
+ ///
+ /// sysex_slider
+ public bool? SysExSlider { get; set; }
+
+ ///
+ /// (PS) Enables .mid SysEx events for Real Drums hi-hat pedal control.
+ ///
+ /// sysex_high_hat_ctrl
+ public bool? SysExHighHatCtrl { get; set; }
+
+ ///
+ /// (PS) Enables .mid SysEx events for Real Drums rimshot hits.
+ ///
+ /// sysex_rimshot
+ public bool? SysExRimshot { get; set; }
+
+ ///
+ /// (PS) Enables .mid SysEx events for guitar open notes.
+ ///
+ /// sysex_open_bass
+ public bool? SysExOpenBass { get; set; }
+
+ ///
+ /// (PS) Enables .mid SysEx events for Pro Guitar/Bass slide directions.
+ ///
+ /// sysex_pro_slide
+ public bool? SysExProSlide { get; set; }
+
+ ///
+ /// (PS) Sound sample set index for guitar.
+ ///
+ /// guitar_type
+ public long? GuitarType { get; set; }
+
+ ///
+ /// (PS) Sound sample set index for bass.
+ ///
+ /// bass_type
+ public long? BassType { get; set; }
+
+ ///
+ /// (PS) Sound sample set index for drums.
+ ///
+ /// kit_type
+ public long? KitType { get; set; }
+
+ ///
+ /// (PS) Sound sample set index for keys.
+ ///
+ /// keys_type
+ public long? KeysType { get; set; }
+
+ ///
+ /// (PS) Sound sample set index for dance.
+ ///
+ /// dance_type
+ public long? DanceType { get; set; }
+
+ #endregion
+
+ #region Images and Other Resources
+
+ ///
+ /// Name of an icon image to display for this song.
+ /// Included in either the chart folder or the game the chart was made for, or sourced from this repository of icons.
+ ///
+ /// icon
+#if NET48
+ public string Icon { get; set; }
+#else
+ public string? Icon { get; set; }
+#endif
+
+ ///
+ /// Name for a background image file.
+ ///
+ /// background
+#if NET48
+ public string Background { get; set; }
+#else
+ public string? Background { get; set; }
+#endif
+
+ ///
+ /// Name for a background video file.
+ ///
+ /// video
+#if NET48
+ public string Video { get; set; }
+#else
+ public string? Video { get; set; }
+#endif
+
+ ///
+ /// Name for a background video file.
+ ///
+ /// video_loop
+ public bool? VideoLoop { get; set; }
+
+ ///
+ /// Timestamp in milliseconds where playback of an included video will start. Can be negative.
+ /// This tag controls the time relative to the video, not relative to the chart. Negative values will delay the video, positive values will make the video be at a further point in when the chart starts.
+ ///
+ /// video_start_time
+ public long? VideoStartTime { get; set; }
+
+ ///
+ /// Timestamp in milliseconds where playback of an included video will end. -1 means no time is specified.
+ /// This is assumed to also be relative to the video, not the chart.
+ ///
+ /// video_end_time
+ public long? VideoEndTime { get; set; }
+
+ ///
+ /// Name for a cover image file.
+ ///
+ /// cover
+#if NET48
+ public string Cover { get; set; }
+#else
+ public string? Cover { get; set; }
+#endif
+
+ #endregion
+
+ #region Images and Other Resources (Game-Specific)
+
+ ///
+ /// (PS) Name for banner A.
+ ///
+ /// link_name_a
+#if NET48
+ public string LinkNameA { get; set; }
+#else
+ public string? LinkNameA { get; set; }
+#endif
+
+ ///
+ /// (PS) Name for banner B.
+ ///
+ /// link_name_b
+#if NET48
+ public string LinkNameB { get; set; }
+#else
+ public string? LinkNameB { get; set; }
+#endif
+
+ ///
+ /// (PS) Link that clicking banner A will open.
+ ///
+ /// banner_link_a
+#if NET48
+ public string BannerLinkA { get; set; }
+#else
+ public string? BannerLinkA { get; set; }
+#endif
+
+ ///
+ /// (PS) Link that clicking banner B will open.
+ ///
+ /// banner_link_b
+#if NET48
+ public string BannerLinkB { get; set; }
+#else
+ public string? BannerLinkB { get; set; }
+#endif
+
+ #endregion
+
+ #region Miscellaneous (Game-Specific)
+
+ ///
+ /// (FoFiX) High score data.
+ ///
+ /// scores
+#if NET48
+ public string Scores { get; set; }
+#else
+ public string? Scores { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) Additional score data.
+ ///
+ /// scores_ext
+#if NET48
+ public string ScoresExt { get; set; }
+#else
+ public string? ScoresExt { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) Play count.
+ ///
+ /// count
+ public long? Count { get; set; }
+
+ ///
+ /// (PS) Player's rating of the song
+ ///
+ /// rating
+ public long? Rating { get; set; }
+
+ ///
+ /// (FoFiX) Career ID for this song.
+ ///
+ /// unlock_id
+#if NET48
+ public string UnlockId { get; set; }
+#else
+ public string? UnlockId { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) The career ID that must be completed to unlock this song.
+ ///
+ /// unlock_require
+#if NET48
+ public string UnlockRequire { get; set; }
+#else
+ public string? UnlockRequire { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) Text to display if the song is locked.
+ ///
+ /// unlock_text
+#if NET48
+ public string UnlockText { get; set; }
+#else
+ public string? UnlockText { get; set; }
+#endif
+
+ ///
+ /// (FoFiX) Indicates if the song is unlocked.
+ ///
+ /// unlock_completed
+ public long? UnlockCompleted { get; set; }
+
+ ///
+ /// (Editor on Fire) Sets a velocity number for drums accent notes.
+ ///
+ /// eof_midi_import_drum_accent_velocity
+ public long? EoFMidiImportDrumAccentVelocity { get; set; }
+
+ ///
+ /// (Editor on Fire) Sets a velocity number for drums ghost notes.
+ ///
+ /// eof_midi_import_drum_ghost_velocity
+ public long? EoFMidiImportDrumGhostVelocity { get; set; }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Charts/TitlesIni.cs b/Charts/TitlesIni.cs
new file mode 100644
index 0000000..b642a37
--- /dev/null
+++ b/Charts/TitlesIni.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace SabreTools.Models.Charts
+{
+ ///
+ /// [titles]
+ internal class TitlesIni
+ {
+ ///
+ /// A space-separated list of .ini sections to include in the career.
+ ///
+ /// sections
+#if NET48
+ public string[] SectionList { get; set; }
+#else
+ public string[]? SectionList { get; set; }
+#endif
+
+ ///
+ /// `name` - Display name of the tier.
+ /// `unlock_id` - Name used for associating a song with this tier, and for checking unlock requirements.
+ ///
+#if NET48
+ public Dictionary Sections { get; set; }
+#else
+ public Dictionary? Sections { get; set; }
+#endif
+ }
+}
\ No newline at end of file