// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; using osu.Framework.Threading; namespace osu.Game.Audio { [LongRunningLoad] public abstract partial class PreviewTrack : Component { /// /// Invoked when this has stopped playing. /// Not invoked in a thread-safe context. /// public event Action? Stopped; /// /// Invoked when this has started playing. /// Not invoked in a thread-safe context. /// public event Action? Started; protected Track? Track { get; private set; } private bool hasStarted; [BackgroundDependencyLoader] private void load() { Track = GetTrack(); if (Track != null) Track.Completed += Stop; } /// /// Length of the track. /// public double Length => Track?.Length ?? 0; /// /// The current track time. /// public double CurrentTime => Track?.CurrentTime ?? 0; /// /// Whether the track is loaded. /// public bool TrackLoaded => Track?.IsLoaded ?? false; /// /// Whether the track is playing. /// public bool IsRunning => Track?.IsRunning ?? false; private ScheduledDelegate? startDelegate; /// /// Starts playing this . /// /// Whether the track is started or already playing. public bool Start() { if (Track == null) return false; startDelegate = Schedule(() => { if (hasStarted) return; hasStarted = true; Track.Restart(); Started?.Invoke(); }); return true; } /// /// Stops playing this . /// public void Stop() { startDelegate?.Cancel(); if (Track == null) return; if (!hasStarted) return; hasStarted = false; // This pre-check is important, fixes a BASS deadlock in some scenarios. if (!Track.HasCompleted) { Track.Stop(); // Ensure the track is reset immediately on stopping, so the next time it is started it has a correct time value. Track.Seek(0); } Stopped?.Invoke(); } /// /// Retrieves the audio track. /// protected abstract Track? GetTrack(); protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); Stop(); Track?.Dispose(); } } }