/// <summary> /// Physically deletes a song file. This will also remove it from the list of /// loaded GameSongs. The song file is located by the GameSong's DefinitionFile /// and Path fields. /// </summary> /// <param name="song">The GameSong to remove and delete.</param> /// <param name="deleteAudio">Whether the GameSong's audio file should be deleted as well.</param> /// <remarks>If deleteAudio is set to true and the folder containing the SongFile is empty /// after the deletion, that folder will be deleted as well.</remarks> /// <returns>"" if deletion was successful, or the error message encountered if something /// went wrong.</returns> public string DeleteSongFile(GameSong song, bool deleteAudio) { try { var existingSongFile = GetBySongFile(song.Path, song.AudioFile); if (existingSongFile != null) { Log.AddMessage("Deleting song file: " + existingSongFile.Path + "\\" + existingSongFile.DefinitionFile, LogLevel.INFO); RemoveSong(existingSongFile); } File.Delete(song.Path + "\\" + song.DefinitionFile); if ((deleteAudio) && File.Exists(song.Path + "\\" + song.AudioFile)) { AudioManager.ReleaseSound(song.Path + "\\" + song.AudioFile); File.Delete(song.Path + "\\" + song.AudioFile); if (Directory.GetFiles(song.Path).Length == 0) { Directory.Delete(song.Path); } } Log.AddMessage("Song deleted successfully.", LogLevel.INFO); return(""); } catch (Exception ex) { return(ex.Message); } }
/// <summary> /// Begins playback of a specific GameSong. The song's audio is loaded into memory, which will /// cause noticable loading time but improve performance during gameplay. /// </summary> /// <param name="song">The GameSong to begin playback.</param> /// <returns>The Channel ID used by the AudioManager for playback of the song's audio.</returns> public int PlaySong(GameSong song) { if (_songChannelIndex != -1) { StopCurrentSong(); } _songChannelIndex = AudioManager.PlaySoundEffect(song.Path + "\\" + song.AudioFile, false, true); //TODO: Fade in if appropriate. AudioManager.SetPosition(_songChannelIndex, Math.Max(0.0, 1000 * (song.AudioStart - 0.5))); return(_songChannelIndex); }
/// <summary> /// Removes a GameSong from the list of playable songs. The given GameSong's Hashcode is used to find which /// song should be removed. /// </summary> /// <param name="song">The GameSong to remove.</param> public void RemoveSong(GameSong song) { if (_songs.Contains(song)) { _songs.Remove(song); } else { throw new Exception("SongManager does not contain song with hashcode: " + song.GetHashCode()); } }
/// <summary> /// Adds a GameSong to the list of songs available. GameSongs are checked for uniqueness by their Hashcode. /// </summary> /// <param name="song">The GameSong to add.</param> public void AddSong(GameSong song) { if (!_songs.Contains(song)) { _songs.Add(song); } else { Log.AddMessage("Cannot load songfile because another copy is already loaded: " + song.Path + "\\" + song.DefinitionFile, LogLevel.WARN); } }
public bool Equals(GameSong other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return(other.GetHashCode() == this.GetHashCode()); }
/// <summary> /// Automatically splits a song's title into a title and subtitle, by checking if any /// brackets are used. A song with a title "Example (Awesome Mix)" would have its title /// changed to "Example" with "(Awesome Mix)" moved to the Subtitle field. This method /// has no effect on very long titles with no brackets. /// </summary> /// <param name="song">The game that needs to have its title split.</param> public static void SplitTitle(GameSong song) { var title = song.Title; title = title.Replace("[", "("); title = title.Replace("]", ")"); if (title.IndexOf("(") < title.IndexOf(")")) { var length = title.LastIndexOf(")") - title.IndexOf("(") + 1; song.Subtitle = title.Substring(title.IndexOf("("), length); song.Title = title.Substring(0, title.IndexOf("(")); } }
/// <summary> /// Stops both the current channel, as well as the previous channel, instantly. /// </summary> public void StopBoth() { if (_channelIndexPrev != -1) { AudioManager.StopChannel(_channelIndexPrev); _channelIndexPrev = -1; } if (_channelIndexCurrent != -1) { AudioManager.StopChannel(_channelIndexCurrent); _channelIndexCurrent = -1; } _currentSong = null; }
public int PreloadSong(GameSong song) { var filePath = song.Path + "\\" + song.AudioFile; int preloadChannelIndex; if (File.Exists(filePath)) { preloadChannelIndex = AudioManager.PlaySoundEffect(song.Path + "\\" + song.AudioFile, false, true, true); _cachedAudioStart = Math.Max(0.0, 1000 * (song.AudioStart - 0.5)); } else { preloadChannelIndex = AudioManager.PlayFallbackSoundEffect(true); } return(preloadChannelIndex); }
/// <summary> /// Returns a 'blank' GameSong with all fields written with Default values. /// Note that no fields are returned null EXCEPT for the DefinitionFile, by design. /// </summary> /// <returns></returns> public static GameSong LoadDefaults() { var gs = new GameSong { BPMs = new Dictionary <double, double>(), Stops = new Dictionary <double, double>(), DefinitionFile = null, Length = 0.0, Offset = 0.0, AudioStart = 0.0, Path = "", AudioFile = "", AudioFileMD5 = "", Subtitle = "", Title = "" }; gs.BPMs.Add(0.0, 0.0); return(gs); }
/// <summary> /// Changes the currently playing song preview to the GameSong provided. /// The provided song will fade in. If another song preview is playing, it /// will be crossfaded out. /// </summary> /// <param name="song">The GameSong to preview.</param> /// <param name="force">Whether the provided game song should be played regardless of whether it /// was already playing.</param> /// <param name="slow">Whether the provided game song should be played at slow speed (for locked songs) </param> public void SetPreviewedSong(GameSong song, bool force, bool slow) { if ((_currentSong == song) && !force) { return; } var channelId = AudioManager.PlaySoundEffect(song.Path + "\\" + song.AudioFile, false, false, false, 0); SetNewChannel(channelId); if (channelId == -1) { return; } AudioManager.SetPosition(channelId, song.Offset * 1000); AudioManager.SetChannelVolume(channelId, 0.0f); if (slow) { AudioManager.SetChannelSpeed(channelId, 0.333f); } _currentSong = song; }
public bool ValidateSongFile(GameSong song) { string dummy; return(ValidateSongFile(song, out dummy)); }
/// <summary> /// Performs a variety of validation checks on a given GameSong, to determine whether it is valid and /// playable. The physical location of the .sng file is determined from the provided GameSong's /// Path and DefinitionFile properties. /// </summary> /// <param name="song">The GameSong to check for validity.</param> /// <param name="message">A message explaining why the song is invalid (output parameter)</param> /// <returns>Whether the GameSong provided is valid and playable.</returns> public bool ValidateSongFile(GameSong song, out string message) { message = "No errors found."; if (string.IsNullOrEmpty(song.AudioFile)) { message = "No audio file specified."; return(false); } var path = song.Path + "\\" + song.AudioFile; if (!File.Exists(path)) { message = "Couldn't find audio file specified." + path; return(false); } if (String.IsNullOrEmpty(song.Title)) { message = "Song does not have a title."; return(false); } if (String.IsNullOrEmpty(song.Artist)) { message = "Song does not have an artist."; } if (song.Offset < 1) { message = "Offset position is invalid. Must be at least one second into the song."; return(false); } if ((song.Length <= 0) || (song.Length <= song.Offset)) { message = "Length is not specified or invalid. Must be higher than Offset."; return(false); } if (song.StartBPM <= 0) { message = "BPM is not specified or invalid. Must be more than zero."; return(false); } if ((song.AudioStart < 0.0) || (song.AudioStart > song.Offset)) { message = "Audio start position is invalid. Must be earlier than offset."; return(false); } switch (SettingsManager.Get <int>("SongMD5Behaviour")) { //WARN ONLY case 1: if (!(song.VerifyMD5())) { message = "Audio File MD5 checksum is invalid. This most likely means that the wrong audio file is being used."; } break; //WARN AND EXCLUDE case 2: if (!(song.VerifyMD5())) { message = "Audio File MD5 checksum is invalid and was not loaded. This most likely means that the wrong audio file is being used."; return(false); } break; //AUTO CORRECT case 3: if (!(song.VerifyMD5())) { song.SetMD5(); SaveToFile(song); message = "Audio File MD5 checksum is invalid and has been overridden, since 'Song Audio Validation' has been set to 'auto correct'."; } break; } return(true); }
/// <summary> /// Saves a GameSong object to a file. Note that the filename is taken from the GameSong /// object itself. /// </summary> /// <param name="song">The GameSong to save to file.</param> public void SaveToFile(GameSong song) { Loaders["*.sng"].SaveToFile(song); Log.AddMessage("Song saved successfully: " + song.Path + "\\" + song.DefinitionFile, LogLevel.INFO); }