// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Utils; namespace osu.Game.Audio { /// <summary> /// Describes a gameplay hit sample. /// </summary> [Serializable] public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo> { public const string HIT_NORMAL = @"hitnormal"; public const string HIT_WHISTLE = @"hitwhistle"; public const string HIT_FINISH = @"hitfinish"; public const string HIT_CLAP = @"hitclap"; public const string BANK_NORMAL = @"normal"; public const string BANK_SOFT = @"soft"; public const string BANK_DRUM = @"drum"; // new sample used exclusively by taiko for now. public const string HIT_FLOURISH = "hitflourish"; // new bank used exclusively by taiko for now. public const string BANK_STRONG = @"strong"; /// <summary> /// All valid sample addition constants. /// </summary> public static readonly string[] ALL_ADDITIONS = [HIT_WHISTLE, HIT_FINISH, HIT_CLAP]; /// <summary> /// All valid bank constants. /// </summary> public static readonly string[] ALL_BANKS = [BANK_NORMAL, BANK_SOFT, BANK_DRUM]; /// <summary> /// The name of the sample to load. /// </summary> public readonly string Name; /// <summary> /// The bank to load the sample from. /// </summary> public readonly string Bank; /// <summary> /// An optional suffix to provide priority lookup. Falls back to non-suffixed <see cref="Name"/>. /// </summary> public readonly string? Suffix; /// <summary> /// The sample volume. /// </summary> public int Volume { get; } /// <summary> /// Whether this sample should automatically assign the bank of the normal sample whenever it is set in the editor. /// </summary> public bool EditorAutoBank { get; } public HitSampleInfo(string name, string bank = SampleControlPoint.DEFAULT_BANK, string? suffix = null, int volume = 100, bool editorAutoBank = true) { Name = name; Bank = bank; Suffix = suffix; Volume = volume; EditorAutoBank = editorAutoBank; } /// <summary> /// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first). /// </summary> [JsonIgnore] public virtual IEnumerable<string> LookupNames { get { if (!string.IsNullOrEmpty(Suffix)) yield return $"Gameplay/{Bank}-{Name}{Suffix}"; yield return $"Gameplay/{Bank}-{Name}"; yield return $"Gameplay/{Name}"; } } /// <summary> /// Creates a new <see cref="HitSampleInfo"/> with overridden values. /// </summary> /// <param name="newName">An optional new sample name.</param> /// <param name="newBank">An optional new sample bank.</param> /// <param name="newSuffix">An optional new lookup suffix.</param> /// <param name="newVolume">An optional new volume.</param> /// <param name="newEditorAutoBank">An optional new editor auto bank flag.</param> /// <returns>The new <see cref="HitSampleInfo"/>.</returns> public virtual HitSampleInfo With(Optional<string> newName = default, Optional<string> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default, Optional<bool> newEditorAutoBank = default) => new HitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newSuffix.GetOr(Suffix), newVolume.GetOr(Volume), newEditorAutoBank.GetOr(EditorAutoBank)); public virtual bool Equals(HitSampleInfo? other) => other != null && Name == other.Name && Bank == other.Bank && Suffix == other.Suffix; public override bool Equals(object? obj) => obj is HitSampleInfo other && Equals(other); public override int GetHashCode() => HashCode.Combine(Name, Bank, Suffix); } }